Как создать задержку в Swift?
Я хочу приостановить свое приложение в определенный момент. Другими словами, Я хочу, чтобы мое приложение выполнило код, но затем в определенный момент приостановите его на 4 секунды, а затем продолжите работу с остальной частью кода. Как я могу это сделать?
Я использую Swift.
10 ответов:
вместо сна, который будет блокировать вашу программу при вызове из потока пользовательского интерфейса, рассмотрите возможность использования
NSTimerили таймер отправки.но, если вам действительно нужна задержка в текущем потоке:
... { sleep(4) }использует
sleepфункция из UNIX.
С помощью
dispatch_afterблок в большинстве случаев лучше, чем при использованииsleep(time)поскольку поток, на котором выполняется сон, блокируется от выполнения другой работы. при использованииdispatch_afterпоток, над которым работает, не блокируется, поэтому он может выполнять другую работу в то же время.
если вы работаете над основным потоком вашего приложения, используяsleep(time)плохо для пользовательского опыта вашего приложения, поскольку пользовательский интерфейс не отвечает в течение этого времени.
Отправка после графиков выполнения блок кода, вместо замораживания потока:Swift ≥ 3.0
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(4), execute: { // Put your code which should be executed with a delay here })Swift
let time = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 4 * Int64(NSEC_PER_SEC)) dispatch_after(time, dispatch_get_main_queue()) { // Put your code which should be executed with a delay here }
Я согласен с Палле, что с помощью
dispatch_afterи хороший выбор здесь. Но вам, вероятно, не нравятся вызовы GCD, поскольку они довольно раздражает писать. Вместо этого вы можете добавить это удобный помощник:public func delay(bySeconds seconds: Double, dispatchLevel: DispatchLevel = .main, closure: @escaping () -> Void) { let dispatchTime = DispatchTime.now() + seconds dispatchLevel.dispatchQueue.asyncAfter(deadline: dispatchTime, execute: closure) } public enum DispatchLevel { case main, userInteractive, userInitiated, utility, background var dispatchQueue: DispatchQueue { switch self { case .main: return DispatchQueue.main case .userInteractive: return DispatchQueue.global(qos: .userInteractive) case .userInitiated: return DispatchQueue.global(qos: .userInitiated) case .utility: return DispatchQueue.global(qos: .utility) case .background: return DispatchQueue.global(qos: .background) } } }теперь ты просто задержите свой код в фоновом потоке такой:
delay(bySeconds: 1.5, dispatchLevel: .background) { // delayed code that will run on background thread }задержка кода на основной поток еще проще:
delay(bySeconds: 1.5) { // delayed code, by default run in main thread }
если вы предпочитаете рамки это также имеет некоторые более удобные функции, то проверка HandySwift. Вы можете добавить его в проект через Карфаген затем используйте его точно так же, как в приведенных выше примерах:
import HandySwift delay(by: .seconds(1.5)) { // delayed code }
сравнение различных подходов в swift 3.0
1. Спи
этот метод не имеет обратного вызова. Поместите коды непосредственно после этой строки, которая будет выполнена через 4 секунды. Это остановит пользователя от итерации с элементами пользовательского интерфейса, такими как кнопка test, пока не пройдет время. Хотя кнопка как бы заморожена, когда начинается сон, другие элементы, такие как индикатор активности, все еще вращаются без замораживания. Вы не можете вызвать это действие снова во время сна.
sleep(4) print("done")//Do stuff here2. Отправка, выполнение и таймер
эти три метода работают аналогично, все они работают в фоновом потоке с обратными вызовами, просто с разным синтаксисом и немного разными функциями.
отправка обычно используется для запуска чего-то в фоновом потоке. Он имеет обратный вызов как часть вызова функции
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(4), execute: { print("done") })выполнить на самом деле упрощенный таймер. Он устанавливает таймер с задержкой, а затем запускает функцию с помощью селектора.
perform(#selector(callback), with: nil, afterDelay: 4.0) func callback() { print("done") }}и, наконец, таймер также предоставляет возможность повторить обратный вызов, который не является полезным в этом случае
Timer.scheduledTimer(timeInterval: 4, target: self, selector: #selector(callback), userInfo: nil, repeats: false) func callback() { print("done") }}для всех этих трех методов, когда вы нажимаете на кнопку, чтобы вызвать их, пользовательский интерфейс не будет замораживаться, и вы можете нажать на него снова. Если вы снова нажмете на кнопку, будет установлен другой таймер, и обратный вызов будет запущен дважды.
В заключение
ни один из четырех методов не работает достаточно хорошо сами по себе.
sleepотключить взаимодействие с пользователем, поэтому экран "замерзает"(на самом деле нет) и приводит к плохому пользовательскому опыту. Другие три метода не будут замораживать экран, но вы можете запускать их несколько раз, и в большинстве случаев вы хотите подождать, пока не получите обратный вызов, прежде чем позволить пользователю сделать снова звонок.таким образом, лучший дизайн будет использовать один из трех асинхронных методов с блокировкой экрана. Когда пользователь нажимает на кнопку, весь экран с каким-то полупрозрачным видом с вращающимся индикатором активности сверху, сообщая пользователю, что нажатие кнопки обрабатывается. Затем снимите просмотра и индикатор в функции обратного вызова, сообщая пользователю, что действие правильно, и т. д.
NSTimer
ответ @nneonneo предложил использовать
NSTimerно не показал, как это сделать. Это основной синтаксис:let delay = 0.5 // time in seconds NSTimer.scheduledTimerWithTimeInterval(delay, target: self, selector: #selector(myFunctionName), userInfo: nil, repeats: false)вот очень простой проект, чтобы показать, как он может быть использован. При нажатии кнопки запускается таймер, который вызовет функцию с задержкой в полсекунды.
import UIKit class ViewController: UIViewController { var timer = NSTimer() let delay = 0.5 // start timer when button is tapped @IBAction func startTimerButtonTapped(sender: UIButton) { // cancel the timer in case the button is tapped multiple times timer.invalidate() // start the timer timer = NSTimer.scheduledTimerWithTimeInterval(delay, target: self, selector: #selector(delayedAction), userInfo: nil, repeats: false) } // function to be called after the delay func delayedAction() { print("action has started") } }используя
dispatch_time(например, ответ Палле) является еще одним допустимым вариантом. Однако, это трудно отменить. СNSTimer, чтобы отменить отложенное событие, прежде чем это произойдет, все, что вам нужно сделать, это позвонитьtimer.invalidate()используя
sleepне рекомендуется, особенно в основном потоке, так как он останавливает всю работу, выполняемую в потоке.посмотреть здесь для моего более полного ответа.
вы также можете сделать это с помощью Swift 3.
выполните функцию после задержки вот так.
override func viewDidLoad() { super.viewDidLoad() self.perform(#selector(ClassName.performAction), with: nil, afterDelay: 2.0) } @objc func performAction() { //This function will perform after 2 seconds print("Delayed") }
попробуйте следующую реализацию в Swift 3.0
func delayWithSeconds(_ seconds: Double, completion: @escaping () -> ()) { DispatchQueue.main.asyncAfter(deadline: .now() + seconds) { completion() } }использование
delayWithSeconds(1) { //Do something }
DispatchQueue.global(qos: .background).async { sleep(4) print("Active after 4 sec, and doesn't block main") DispatchQueue.main.async{ //do stuff in the main thread here } }
чтобы создать простую временную задержку, вы можете импортировать Darwin, а затем использовать sleep(секунды), чтобы сделать задержку. Однако это занимает всего несколько секунд, поэтому для более точных измерений вы можете импортировать Darwin и использовать usleep(миллионные доли секунды) для очень точного измерения. Чтобы проверить это, я написал:
import Darwin print("This is one.") sleep(1) print("This is two.") usleep(400000) print("This is three.")который печатает, затем ждет 1 сек и печатает, затем ждет 0,4 сек, а затем печатает. Все работало как положено.
Это самый простой
delay(0.3, closure: { // put her any code you want to fire it with delay button.removeFromSuperview() })


Comments