Как создать задержку в 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
}
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
is хороший выбор здесь. Но вам, вероятно, не нравятся вызовы 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. Спи!--7-->
этот метод не имеет обратного вызова. Положите коды сразу после этой строки, который нужно выполнить в 4 секундах. Это остановит пользователя от итерации с элементами пользовательского интерфейса, такими как кнопка test, пока не пройдет время. Хотя кнопка как бы заморожена, когда начинается сон, другие элементы, такие как индикатор активности, все еще вращаются без замораживания. Вы не можете запустить это действие снова во время сна.
sleep(4)
print("done")//Do stuff here
2. Отправка, выполнение и таймер
эти три метода работают аналогично, все они работают в фоновом потоке с обратными вызовами, просто с другим синтаксисом и немного разными функциями.
Dispatch обычно используется для запуска чего-то в фоновом потоке. Он имеет обратный вызов как часть вызова функции
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(секунды), чтобы сделать задержку. Это занимает всего несколько секунд, поэтому для более точных измерений вы можете импортировать Дарвина и использовать 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()
})