Как создать задержку в Swift?

Я хочу приостановить свое приложение с определенной точки. Другими словами, я хочу, чтобы мое приложение выполнило код, но затем в определенный момент остановитесь на 4 секунды, а затем продолжайте работу с остальной частью кода. Как я могу это сделать?

Я использую Swift.

Ответ 1

Вместо сна, который заблокирует вашу программу, если вызван из потока пользовательского интерфейса, рассмотрите возможность использования NSTimer или таймера отправки.

Но если вам действительно нужна задержка в текущем потоке:

... {
    sleep(4)
}

Здесь используется функция sleep из UNIX.

Ответ 2

Использование блока dispatch_after в большинстве случаев лучше, чем использование sleep(time), поскольку поток, в котором выполняется ожидание, заблокирован от выполнения другой работы. при использовании dispatch_after обрабатываемый поток не блокируется, поэтому он может выполнять другую работу в это время.
Если вы работаете с основным потоком своего приложения, использование sleep(time) вредно для пользовательского интерфейса вашего приложения, поскольку пользовательский интерфейс в это время не отвечает.

Отправка после планирования выполнения блока кода вместо замораживания потока:

Swift ≥ 3.0

let seconds = 4.0
DispatchQueue.main.asyncAfter(deadline: .now() + seconds) {
    // Put your code which should be executed with a delay here
}

Swift & lt; 3,0

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
}

Ответ 3

Сравнение различных подходов в swift 3.0

1. Сон

Этот метод не имеет обратного вызова. Поместите коды непосредственно после того, как эта строка будет выполнена через 4 секунды. Это остановит пользователя от итерации с элементами пользовательского интерфейса, такими как кнопка тестирования, до тех пор, пока время не исчезнет. Несмотря на то, что кнопка слегка замерзает, когда происходит сон, другие элементы, такие как индикатор активности, продолжают вращаться без замерзания. Вы не можете запускать это действие снова во время сна.

sleep(4)
print("done")//Do stuff here

введите описание изображения здесь

2. Отправка, выполнение и таймер

Эти три метода работают аналогично, все они работают в фоновом потоке с обратными вызовами, просто с различным синтаксисом и немного разными функциями.

Отправка обычно используется для запуска чего-то в фоновом потоке. Он имеет обратный вызов как часть вызова функции

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 отключит взаимодействие пользователя, поэтому экран "зависает" (на самом деле) и не дает плохих результатов. Остальные три метода не будут замораживать экран, но вы можете запускать их несколько раз, и в большинстве случаев вы хотите подождать, пока не получите обратный вызов, прежде чем разрешить пользователю совершать вызов еще раз.

Таким образом, лучший дизайн будет использовать один из трех асинхронных методов с блокировкой экрана. Когда пользователь нажимает на кнопку, закрывайте весь экран с помощью полупрозрачного вида с индикатором активности вращения, указав пользователю, что нажатие кнопки обрабатывается. Затем удалите представление и индикатор в функции обратного вызова, сообщив пользователю, что действие правильно обработано и т.д.

Ответ 4

Я согласен с Palle, что использование 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
}

Если вы предпочитаете Framework, в котором также есть несколько удобных функций, обратитесь к HandySwift. Вы можете добавить его в свой проект через Carthage или Accio, а затем использовать его точно так же, как в примерах выше:

import HandySwift    

delay(by: .seconds(1.5)) { 
    // delayed code
}

Ответ 5

Вы также можете сделать это с помощью 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")
        }

Ответ 6

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 (как в Palle answer) является еще одним допустимым вариантом. Однако трудно отменить. С NSTimer, чтобы отменить событие с задержкой до его появления, вам нужно только позвонить

timer.invalidate()

Использование sleep не рекомендуется, особенно в основном потоке, так как он останавливает всю работу, выполняемую в потоке.

См. здесь для моего более полного ответа.

Ответ 7

В Swift 4.2 и Xcode 10.1

У вас есть 4 способа отложить. Из этого варианта 1 предпочтительно вызывать или выполнять функцию через некоторое время. sleep() используется меньше всего.

Вариант 1.

DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
    self.yourFuncHere()
}
//Your function here    
func yourFuncHere() {

}

Вариант 2.

perform(#selector(yourFuncHere2), with: nil, afterDelay: 5.0)

//Your function here  
@objc func yourFuncHere2() {
    print("this is...")
}

Вариант 3.

Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(yourFuncHere3), userInfo: nil, repeats: false)

//Your function here  
@objc func yourFuncHere3() {

}

Вариант 4.

sleep(5)

Если вы хотите через некоторое время вызвать функцию для выполнения чего-либо, не используйте sleep.

Ответ 8

Попробуйте выполнить следующую реализацию в Swift 3.0

func delayWithSeconds(_ seconds: Double, completion: @escaping () -> ()) {
    DispatchQueue.main.asyncAfter(deadline: .now() + seconds) { 
        completion()
    }
}

Использование

delayWithSeconds(1) {
   //Do something
}

Ответ 9

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
    }
}

Ответ 10

Если вам нужно установить задержку менее секунды, нет необходимости устанавливать параметр .seconds. Надеюсь это кому-нибудь пригодится.

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
        // your code hear
})

Ответ 11

Вы можете легко создать расширение для использования функции задержки (Синтаксис: Swift 4. 2+)

extension UIViewController {
    func delay(_ delay:Double, closure:@escaping ()->()) {
        DispatchQueue.main.asyncAfter(
            deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: closure)
    }
}

Как использовать в UIViewController

self.delay(0.1, closure: {
   //execute code
})

Ответ 12

Если ваш код уже выполняется в фоновом потоке, приостановите поток с помощью этого метода в Foundation: Thread.sleep(forTimeInterval:)

Например:

DispatchQueue.global(qos: .userInitiated).async {

    // Code is running in a background thread already so it is safe to sleep
    Thread.sleep(forTimeInterval: 4.0)
}

(Смотрите другие ответы для предложений, когда ваш код работает в главном потоке.)

Ответ 13

Чтобы создать простую временную задержку, вы можете импортировать Darwin, а затем использовать sleep (seconds) для выполнения задержки. Это займет всего несколько секунд, однако, для более точных измерений вы можете импортировать Дарвина и использовать usleep (миллионные доли секунды) для очень точного измерения. Чтобы проверить это, я написал:

import Darwin
print("This is one.")
sleep(1)
print("This is two.")
usleep(400000)
print("This is three.")

Который печатает, затем ждет 1 секунду и печатает, затем ждет 0,4 секунды, а затем печатает. Все работали как ожидалось.

Ответ 14

это самый простой

    delay(0.3, closure: {
        // put her any code you want to fire it with delay
        button.removeFromSuperview()   
    })