Ho esaminato l' iBook di Apple e non sono riuscito a trovarne alcuna definizione:
Qualcuno può spiegare la struttura di dispatch_after
?
dispatch_after(<#when: dispatch_time_t#>, <#queue: dispatch_queue_t?#>, <#block: dispatch_block_t?#>)
Ho esaminato l' iBook di Apple e non sono riuscito a trovarne alcuna definizione:
Qualcuno può spiegare la struttura di dispatch_after
?
dispatch_after(<#when: dispatch_time_t#>, <#queue: dispatch_queue_t?#>, <#block: dispatch_block_t?#>)
Risposte:
Un'idea più chiara della struttura:
dispatch_after(when: dispatch_time_t, queue: dispatch_queue_t, block: dispatch_block_t?)
dispatch_time_t
è un UInt64
. In dispatch_queue_t
realtà il tipo è aliasato per un NSObject
, ma dovresti semplicemente usare i tuoi metodi GCD familiari per ottenere le code. Il blocco è una chiusura Swift. In particolare, dispatch_block_t
è definito come () -> Void
, che equivale a () -> ()
.
Esempio di utilizzo:
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue()) {
print("test")
}
MODIFICARE:
Consiglio di usare la delay
funzione davvero bella di @ matt .
EDIT 2:
In Swift 3, ci saranno nuovi wrapper per GCD. Vedi qui: https://github.com/apple/swift-evolution/blob/master/proposals/0088-libdispatch-for-swift3.md
L'esempio originale verrebbe scritto come segue in Swift 3:
let deadlineTime = DispatchTime.now() + .seconds(1)
DispatchQueue.main.asyncAfter(deadline: deadlineTime) {
print("test")
}
Si noti che è possibile scrivere la deadlineTime
dichiarazione come DispatchTime.now() + 1.0
e ottenere lo stesso risultato perché l' +
operatore viene sovrascritto come segue (in modo simile per -
):
func +(time: DispatchTime, seconds: Double) -> DispatchTime
func +(time: DispatchWalltime, interval: DispatchTimeInterval) -> DispatchWalltime
Ciò significa che se non si utilizza DispatchTimeInterval
enum
e si scrive semplicemente un numero, si presume che si stiano utilizzando i secondi.
dispatch_after(1, dispatch_get_main_queue()) { println("test") }
1
in dispatch_after(1, ...
possa creare molta confusione qui. La gente penserà che è un numero di secondi, quando in realtà è nano-secondo . Suggerisco di vedere la risposta di @brindy su come creare correttamente questo numero.
1
a dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
perché causa confusione. La gente potrebbe pensare che non è necessario creare un dispatch_time_t in Swift
Binary operator '+' cannot be applied to operands of type DispatchTime and '_'
sulla linealet delayTime = DispatchTime.now() + .seconds(1.0)
DispatchTime.now() + 1.0
sembra essere l'unico modo per farlo funzionare (non c'è bisogno di .seconds
)
Uso dispatch_after
così spesso che ho scritto una funzione di utilità di livello superiore per semplificare la sintassi:
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
E ora puoi parlare così:
delay(0.4) {
// do stuff
}
Wow, una lingua in cui puoi migliorare la lingua. Cosa potrebbe esserci di meglio?
Sembra quasi non preoccuparsene, ora che hanno migliorato la sintassi della chiamata:
func delay(_ delay:Double, closure:@escaping ()->()) {
let when = DispatchTime.now() + delay
DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}
func delayInSec(delay: Double) -> dispatch_time_t { return dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))) }
return
.).
1.0 ~~ { code...}
Swift 3+
Questo è semplicissimo ed elegante in Swift 3+:
DispatchQueue.main.asyncAfter(deadline: .now() + 4.5) {
// ...
}
Risposta precedente:
Per espandere la risposta di Cezary, che verrà eseguita dopo 1 nanosecondo, ho dovuto eseguire le seguenti operazioni per eseguire dopo 4 secondi e mezzo.
let delay = 4.5 * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(time, dispatch_get_main_queue(), block)
Modifica: ho scoperto che il mio codice originale era leggermente sbagliato. La digitazione implicita provoca un errore di compilazione se non si esegue il cast di NSEC_PER_SEC su un doppio.
Se qualcuno può suggerire una soluzione più ottimale sarei desideroso di ascoltarlo.
dispatch_get_current_queue()
. Ho usato dispatch_get_main_queue()
invece.
dispatch_get_main_queue()
è sicuramente quello che dovresti usare. Si aggiorna.
La sintassi di Matt è molto bella e se devi invalidare il blocco, potresti voler usare questo:
typealias dispatch_cancelable_closure = (cancel : Bool) -> Void
func delay(time:NSTimeInterval, closure:()->Void) -> dispatch_cancelable_closure? {
func dispatch_later(clsr:()->Void) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(time * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), clsr)
}
var closure:dispatch_block_t? = closure
var cancelableClosure:dispatch_cancelable_closure?
let delayedClosure:dispatch_cancelable_closure = { cancel in
if closure != nil {
if (cancel == false) {
dispatch_async(dispatch_get_main_queue(), closure!);
}
}
closure = nil
cancelableClosure = nil
}
cancelableClosure = delayedClosure
dispatch_later {
if let delayedClosure = cancelableClosure {
delayedClosure(cancel: false)
}
}
return cancelableClosure;
}
func cancel_delay(closure:dispatch_cancelable_closure?) {
if closure != nil {
closure!(cancel: true)
}
}
Utilizzare come segue
let retVal = delay(2.0) {
println("Later")
}
delay(1.0) {
cancel_delay(retVal)
}
Il link sopra sembra essere inattivo. Codice Objc originale da Github
performSelector:afterDelay:
ora è disponibile in Swift 2, quindi puoi annullarlo.
dispatch_source_t
, perché è qualcosa che puoi cancellare).
Apple ha uno snippet dispatch_after per Objective-C :
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(<#delayInSeconds#> * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
<#code to be executed after a specified delay#>
});
Ecco lo stesso frammento portato su Swift 3:
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + <#delayInSeconds#>) {
<#code to be executed after a specified delay#>
}
Un altro modo è estendere Double in questo modo:
extension Double {
var dispatchTime: dispatch_time_t {
get {
return dispatch_time(DISPATCH_TIME_NOW,Int64(self * Double(NSEC_PER_SEC)))
}
}
}
Quindi puoi usarlo in questo modo:
dispatch_after(Double(2.0).dispatchTime, dispatch_get_main_queue(), { () -> Void in
self.dismissViewControllerAnimated(true, completion: nil)
})
Mi piace la funzione di ritardo di Matt, ma per preferenza preferirei limitare il passaggio delle chiusure.
In Swift 3.0
Code di invio
DispatchQueue(label: "test").async {
//long running Background Task
for obj in 0...1000 {
print("async \(obj)")
}
// UI update in main queue
DispatchQueue.main.async(execute: {
print("UI update on main queue")
})
}
DispatchQueue(label: "m").sync {
//long running Background Task
for obj in 0...1000 {
print("sync \(obj)")
}
// UI update in main queue
DispatchQueue.main.sync(execute: {
print("UI update on main queue")
})
}
Spedizione dopo 5 secondi
DispatchQueue.main.after(when: DispatchTime.now() + 5) {
print("Dispatch after 5 sec")
}
Versione Swift 3.0
Dopo la funzione di chiusura, eseguire alcune attività dopo un ritardo sul thread principale.
func performAfterDelay(delay : Double, onCompletion: @escaping() -> Void){
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delay, execute: {
onCompletion()
})
}
Chiamare questa funzione come:
performAfterDelay(delay: 4.0) {
print("test")
}
1) Aggiungi questo metodo come parte dell'estensione UIViewController.
extension UIViewController{
func runAfterDelay(delay: NSTimeInterval, block: dispatch_block_t) {
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)))
dispatch_after(time, dispatch_get_main_queue(), block)
}
}
Chiama questo metodo su VC:
self.runAfterDelay(5.0, block: {
//Add code to this block
print("run After Delay Success")
})
2)
performSelector("yourMethod Name", withObject: nil, afterDelay: 1)
3)
override func viewWillAppear(animated: Bool) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2), dispatch_get_main_queue(), { () -> () in
//Code Here
})
// Forma compatta
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2), dispatch_get_main_queue()) {
//Code here
}
}
Sebbene non sia la domanda originale del PO, alcune NSTimer
domande correlate sono state contrassegnate come duplicati di questa domanda, quindi vale la pena includere unNSTimer
qui risposta.
NSTimer
vs dispatch_after
NSTimer
è più alto livello mentre dispatch_after
è più basso livello.NSTimer
è più facile da cancellare. L'annullamento dispatch_after
richiede la scrittura di più codice .NSTimer
Crea NSTimer
un'istanza.
var timer = NSTimer()
Avvia il timer con il ritardo di cui hai bisogno.
// invalidate the timer if there is any chance that it could have been called before
timer.invalidate()
// delay of 2 seconds
timer = NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: #selector(delayedAction), userInfo: nil, repeats: false)
Aggiungi una funzione da chiamare dopo il ritardo (usando qualunque nome tu abbia usato per il selector
parametro sopra).
func delayedAction() {
print("Delayed action has now started."
}
timer.invalidate()
.repeats: true
.Se si dispone di un evento singolo senza annullamento, non è necessario creare la timer
variabile di istanza. Sarà sufficiente:
NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: #selector(delayedAction), userInfo: nil, repeats: false)
Vedi la mia risposta più completa qui .
Per più funzioni usare questo. Questo è molto utile per usare animazioni o caricatore di attività per funzioni statiche o qualsiasi aggiornamento dell'interfaccia utente.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.9) {
// Call your function 1
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
// Call your function 2
}
}
Ad esempio: utilizzare un'animazione prima che un tableView venga ricaricato. O qualsiasi altro aggiornamento dell'interfaccia utente dopo l'animazione.
*// Start your amination*
self.startAnimation()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.9) {
*// The animation will execute depending on the delay time*
self.stopAnimation()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
*// Now update your view*
self.fetchData()
self.updateUI()
}
}
Questo ha funzionato per me.
Swift 3:
let time1 = 8.23
let time2 = 3.42
// Delay 2 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
print("Sum of times: \(time1 + time2)")
}
Objective-C:
CGFloat time1 = 3.49;
CGFloat time2 = 8.13;
// Delay 2 seconds
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
CGFloat newTime = time1 + time2;
NSLog(@"New time: %f", newTime);
});
Swift 3 e 4:
È possibile creare un'estensione su DispatchQueue e aggiungere un ritardo di funzione che utilizza internamente la funzione DispatchQueue asyncAfter
extension DispatchQueue {
static func delay(_ delay: DispatchTimeInterval, closure: @escaping () -> ()) {
let timeInterval = DispatchTime.now() + delay
DispatchQueue.main.asyncAfter(deadline: timeInterval, execute: closure)
}
}
uso:
DispatchQueue.delay(.seconds(1)) {
print("This is after delay")
}
Un altro aiuto per ritardare il tuo codice che è 100% Swift in uso e facoltativamente consente di scegliere un thread diverso per eseguire il tuo codice ritardato da:
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)
}
}
}
Ora puoi semplicemente ritardare il tuo codice sul thread principale in questo modo:
delay(bySeconds: 1.5) {
// delayed code
}
Se vuoi ritardare il tuo codice su un thread diverso :
delay(bySeconds: 1.5, dispatchLevel: .background) {
// delayed code that will run on background thread
}
Se preferisci un Framework che ha anche alcune funzioni più utili, dai un'occhiata a HandySwift . Puoi aggiungerlo al tuo progetto tramite Cartagine, quindi usarlo esattamente come negli esempi sopra, ad esempio:
import HandySwift
delay(bySeconds: 1.5) {
// delayed code
}
Preferisco sempre usare l'estensione invece delle funzioni gratuite.
Swift 4
public extension DispatchQueue {
private class func delay(delay: TimeInterval, closure: @escaping () -> Void) {
let when = DispatchTime.now() + delay
DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}
class func performAction(after seconds: TimeInterval, callBack: @escaping (() -> Void) ) {
DispatchQueue.delay(delay: seconds) {
callBack()
}
}
}
Utilizzare come segue.
DispatchQueue.performAction(after: 0.3) {
// Code Here
}
Ritardare la chiamata GCD utilizzando asyncAfter in rapido
let delayQueue = DispatchQueue(label: "com.theappmaker.in", qos: .userInitiated)
let additionalTime: DispatchTimeInterval = .seconds(2)
Possiamo ritardare di ** microsecondi , millisecondi , nanosecondi
delayQueue.asyncAfter(deadline: .now() + 0.60) {
print(Date())
}
delayQueue.asyncAfter(deadline: .now() + additionalTime) {
print(Date())
}
In Swift 4
Usa questo frammento:
let delayInSec = 1.0
DispatchQueue.main.asyncAfter(deadline: .now() + delayInSec) {
// code here
print("It works")
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// ...
});
La dispatch_after(_:_:_:)
funzione accetta tre parametri:
un ritardo di
una spedizione in coda
un blocco o una chiusura
La dispatch_after(_:_:_:)
funzione richiama il blocco o la chiusura sulla coda di invio che viene passata alla funzione dopo un determinato ritardo. Si noti che il ritardo viene creato utilizzando ildispatch_time(_:_:)
funzione. Ricordalo perché utilizziamo anche questa funzione in Swift.
Consiglio di passare attraverso il tutorial Tutorial di spedizione Raywenderlich
In Swift 5, utilizza quanto segue:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: closure)
// time gap, specify unit is second
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) {
Singleton.shared().printDate()
}
// default time gap is second, you can reduce it
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
// just do it!
}
utilizzare questo codice per eseguire alcune attività correlate all'interfaccia utente dopo 2,0 secondi.
let delay = 2.0
let delayInNanoSeconds = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)))
let mainQueue = dispatch_get_main_queue()
dispatch_after(delayInNanoSeconds, mainQueue, {
print("Some UI related task after delay")
})
Versione Swift 3.0
Dopo la funzione di chiusura, eseguire alcune attività dopo un ritardo sul thread principale.
func performAfterDelay(delay : Double, onCompletion: @escaping() -> Void){
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delay, execute: {
onCompletion()
})
}
Chiamare questa funzione come:
performAfterDelay(delay: 4.0) {
print("test")
}
Ora più che zucchero sintattico per spedizioni asincrone in Grand Central Dispatch (GCD) in Swift.
aggiungi Podfile
pod 'AsyncSwift'
Quindi, puoi usarlo in questo modo.
let seconds = 3.0
Async.main(after: seconds) {
print("Is called after 3 seconds")
}.background(after: 6.0) {
print("At least 3.0 seconds after previous block, and 6.0 after Async code is called")
}
Swift 4 ha un modo piuttosto breve di farlo:
Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { (timer) in
// Your stuff here
print("hello")
}
Ecco la versione sincrona di asyncAfter in Swift:
let deadline = DispatchTime.now() + .seconds(3)
let semaphore = DispatchSemaphore.init(value: 0)
DispatchQueue.global().asyncAfter(deadline: deadline) {
dispatchPrecondition(condition: .onQueue(DispatchQueue.global()))
semaphore.signal()
}
semaphore.wait()
Insieme a quello asincrono:
let deadline = DispatchTime.now() + .seconds(3)
DispatchQueue.main.asyncAfter(deadline: deadline) {
dispatchPrecondition(condition: .onQueue(DispatchQueue.global()))
}