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




wait some time swift (10)

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

timer.invalidate()

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

Смотрите here для моего более полного ответа.

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

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


В 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 .


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

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

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

Использование блока dispatch_after в большинстве случаев лучше, чем использование sleep(time) как поток, в котором выполняется sleep, заблокирован от выполнения другой работы. при использовании 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 <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
}

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

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

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

delayWithSeconds(1) {
   //Do something
}

Я согласен с 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
}

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

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

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

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


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




delay