Je suis passé par l' iBook d'Apple et trouvé aucune définition de celui-ci:
Quelqu'un peut-il expliquer la structure de dispatch_after
?
dispatch_after(<#when: dispatch_time_t#>, <#queue: dispatch_queue_t?#>, <#block: dispatch_block_t?#>)
Je suis passé par l' iBook d'Apple et trouvé aucune définition de celui-ci:
Quelqu'un peut-il expliquer la structure de dispatch_after
?
dispatch_after(<#when: dispatch_time_t#>, <#queue: dispatch_queue_t?#>, <#block: dispatch_block_t?#>)
Réponses:
Une idée plus claire de la structure:
dispatch_after(when: dispatch_time_t, queue: dispatch_queue_t, block: dispatch_block_t?)
dispatch_time_t
est un UInt64
. Le dispatch_queue_t
est en fait un alias de type pour un NSObject
, mais vous devez simplement utiliser vos méthodes GCD familières pour obtenir les files d'attente. Le bloc est une fermeture Swift. Plus précisément, dispatch_block_t
est défini comme () -> Void
, ce qui équivaut à () -> ()
.
Exemple d'utilisation:
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue()) {
print("test")
}
ÉDITER:
Je recommande d'utiliser la delay
fonction vraiment sympa de @ matt .
EDIT 2:
Dans Swift 3, il y aura de nouveaux wrappers pour GCD. Vois ici: https://github.com/apple/swift-evolution/blob/master/proposals/0088-libdispatch-for-swift3.md
L'exemple d'origine serait écrit comme suit dans Swift 3:
let deadlineTime = DispatchTime.now() + .seconds(1)
DispatchQueue.main.asyncAfter(deadline: deadlineTime) {
print("test")
}
Notez que vous pouvez écrire la deadlineTime
déclaration en tant que DispatchTime.now() + 1.0
et obtenir le même résultat car l' +
opérateur est remplacé comme suit (de même pour -
):
func +(time: DispatchTime, seconds: Double) -> DispatchTime
func +(time: DispatchWalltime, interval: DispatchTimeInterval) -> DispatchWalltime
Cela signifie que si vous n'utilisez pas le DispatchTimeInterval
enum
et écrivez simplement un nombre, on suppose que vous utilisez des secondes.
dispatch_after(1, dispatch_get_main_queue()) { println("test") }
1
de dispatch_after(1, ...
peut causer beaucoup de confusion. Les gens penseront qu'il s'agit d'un nombre de secondes, alors qu'il s'agit en fait de nano-secondes . Je suggère de voir la réponse de @brindy sur la façon de créer correctement ce numéro.
1
en dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
car cela crée de la confusion. Les gens pourraient penser que vous n'avez pas besoin de créer un dispatch_time_t dans Swift
Binary operator '+' cannot be applied to operands of type DispatchTime and '_'
sur la lignelet delayTime = DispatchTime.now() + .seconds(1.0)
DispatchTime.now() + 1.0
semble être le seul moyen de le faire fonctionner (pas besoin .seconds
)
J'utilise dispatch_after
si souvent que j'ai écrit une fonction utilitaire de haut niveau pour simplifier la syntaxe:
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
Et maintenant, vous pouvez parler comme ceci:
delay(0.4) {
// do stuff
}
Wow, une langue où vous pouvez améliorer la langue. Qu'est-ce qui pourrait être mieux?
Cela ne vaut presque pas la peine d'être dérangé, maintenant qu'ils ont amélioré la syntaxe d'appel:
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+
C'est super facile et élégant dans Swift 3+:
DispatchQueue.main.asyncAfter(deadline: .now() + 4.5) {
// ...
}
Réponse plus ancienne:
Pour développer la réponse de Cezary, qui s'exécutera après 1 nanoseconde, j'ai dû faire ce qui suit pour l'exécuter après 4 secondes et demie.
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)
Edit: j'ai découvert que mon code d'origine était légèrement faux. Le typage implicite provoque une erreur de compilation si vous ne transtypez pas NSEC_PER_SEC en Double.
Si quelqu'un peut suggérer une solution plus optimale, je serais ravi de l'entendre.
dispatch_get_current_queue()
. J'ai utilisé à la dispatch_get_main_queue()
place.
dispatch_get_main_queue()
c'est certainement ce que vous devriez utiliser. Mettra à jour.
La syntaxe de matt est très agréable et si vous devez invalider le bloc, vous pouvez utiliser ceci:
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)
}
}
Utilisez comme suit
let retVal = delay(2.0) {
println("Later")
}
delay(1.0) {
cancel_delay(retVal)
}
Le lien ci-dessus semble être en panne. Code Objc original de Github
performSelector:afterDelay:
est désormais disponible dans Swift 2, vous pouvez donc l'annuler.
dispatch_source_t
, car c'est quelque chose que vous pouvez annuler).
Apple a un extrait dispatch_after pour 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#>
});
Voici le même extrait porté sur Swift 3:
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + <#delayInSeconds#>) {
<#code to be executed after a specified delay#>
}
Une autre façon est d'étendre Double comme ceci:
extension Double {
var dispatchTime: dispatch_time_t {
get {
return dispatch_time(DISPATCH_TIME_NOW,Int64(self * Double(NSEC_PER_SEC)))
}
}
}
Ensuite, vous pouvez l'utiliser comme ceci:
dispatch_after(Double(2.0).dispatchTime, dispatch_get_main_queue(), { () -> Void in
self.dismissViewControllerAnimated(true, completion: nil)
})
J'aime la fonction de retard de matt mais juste par préférence, je préfère limiter les fermetures de passage.
Dans Swift 3.0
Files d'attente de répartition
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")
})
}
Envoi après 5 secondes
DispatchQueue.main.after(when: DispatchTime.now() + 5) {
print("Dispatch after 5 sec")
}
Version Swift 3.0
La fonction de fermeture suivante exécute une tâche après un délai sur le thread principal.
func performAfterDelay(delay : Double, onCompletion: @escaping() -> Void){
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delay, execute: {
onCompletion()
})
}
Appelez cette fonction comme:
performAfterDelay(delay: 4.0) {
print("test")
}
1) Ajoutez cette méthode dans le cadre de l'extension 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)
}
}
Appelez cette méthode sur 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
})
// Forme compacte
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2), dispatch_get_main_queue()) {
//Code here
}
}
Bien qu'il ne s'agisse pas de la question d'origine du PO, certaines NSTimer
questions connexes ont été marquées comme des doublons de cette question, il vaut donc la peine d'y inclure une NSTimer
réponse ici.
NSTimer
contre dispatch_after
NSTimer
est de niveau plus élevé tandis que dispatch_after
est de niveau plus bas.NSTimer
est plus facile à annuler. L'annulation dispatch_after
nécessite l'écriture de plus de code .NSTimer
Créez une NSTimer
instance.
var timer = NSTimer()
Démarrez la minuterie avec le retard dont vous avez besoin.
// 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)
Ajoutez une fonction à appeler après le délai (en utilisant le nom que vous avez utilisé pour le selector
paramètre ci-dessus).
func delayedAction() {
print("Delayed action has now started."
}
timer.invalidate()
.repeats: true
.Si vous avez un événement ponctuel sans avoir besoin d'annuler, il n'est pas nécessaire de créer la timer
variable d'instance. Les éléments suivants suffiront:
NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: #selector(delayedAction), userInfo: nil, repeats: false)
Voir ma réponse plus complète ici .
Pour plusieurs fonctions, utilisez ceci. Ceci est très utile pour utiliser des animations ou un chargeur d'activité pour les fonctions statiques ou toute mise à jour de l'interface utilisateur.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.9) {
// Call your function 1
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
// Call your function 2
}
}
Par exemple - Utilisez une animation avant un rechargement de tableView. Ou toute autre mise à jour de l'interface utilisateur après l'animation.
*// 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()
}
}
Cela a fonctionné pour moi.
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)")
}
Objectif 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 & 4:
Vous pouvez créer une extension sur DispatchQueue et ajouter un retard de fonction qui utilise la fonction asyncAfter de DispatchQueue en interne
extension DispatchQueue {
static func delay(_ delay: DispatchTimeInterval, closure: @escaping () -> ()) {
let timeInterval = DispatchTime.now() + delay
DispatchQueue.main.asyncAfter(deadline: timeInterval, execute: closure)
}
}
utilisation:
DispatchQueue.delay(.seconds(1)) {
print("This is after delay")
}
Un autre assistant pour retarder votre code qui est 100% Swift dans l'utilisation et permet éventuellement de choisir un thread différent pour exécuter votre code retardé à partir de:
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)
}
}
}
Maintenant, vous retardez simplement votre code sur le fil principal comme ceci:
delay(bySeconds: 1.5) {
// delayed code
}
Si vous souhaitez retarder votre code sur un autre thread :
delay(bySeconds: 1.5, dispatchLevel: .background) {
// delayed code that will run on background thread
}
Si vous préférez un Framework qui possède également des fonctionnalités plus pratiques, passez à HandySwift . Vous pouvez l'ajouter à votre projet via Carthage puis l'utiliser exactement comme dans les exemples ci-dessus, par exemple:
import HandySwift
delay(bySeconds: 1.5) {
// delayed code
}
Je préfère toujours utiliser l'extension au lieu des fonctions gratuites.
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()
}
}
}
Utilisez comme suit.
DispatchQueue.performAction(after: 0.3) {
// Code Here
}
Retarder l'appel GCD en utilisant asyncAfter dans swift
let delayQueue = DispatchQueue(label: "com.theappmaker.in", qos: .userInitiated)
let additionalTime: DispatchTimeInterval = .seconds(2)
Nous pouvons retarder comme ** microsecondes , millisecondes , nanosecondes
delayQueue.asyncAfter(deadline: .now() + 0.60) {
print(Date())
}
delayQueue.asyncAfter(deadline: .now() + additionalTime) {
print(Date())
}
Dans Swift 4
Utilisez cet extrait:
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(_:_:_:)
fonction prend trois paramètres:
un retard
une file d'attente de répartition
un bloc ou une fermeture
La dispatch_after(_:_:_:)
fonction appelle le bloc ou la fermeture de la file d'attente de répartition qui est passé à la fonction après un délai donné. Notez que le retard est créé à l'aide de la dispatch_time(_:_:)
fonction. N'oubliez pas ceci car nous utilisons également cette fonction dans Swift.
Je recommande de suivre le tutoriel Raywenderlich Dispatch tutorial
Dans Swift 5, utilisez ce qui suit:
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!
}
utilisez ce code pour effectuer une tâche liée à l'interface utilisateur après 2,0 secondes.
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")
})
Version Swift 3.0
La fonction de fermeture suivante exécute une tâche après un délai sur le thread principal.
func performAfterDelay(delay : Double, onCompletion: @escaping() -> Void){
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delay, execute: {
onCompletion()
})
}
Appelez cette fonction comme:
performAfterDelay(delay: 4.0) {
print("test")
}
Maintenant plus que du sucre syntaxique pour les envois asynchrones dans Grand Central Dispatch (GCD) dans Swift.
ajouter Podfile
pod 'AsyncSwift'
Ensuite, vous pouvez l'utiliser comme ça.
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 a un moyen assez court de le faire:
Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { (timer) in
// Your stuff here
print("hello")
}
Voici la version synchrone de asyncAfter dans 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()
Avec un asynchrone:
let deadline = DispatchTime.now() + .seconds(3)
DispatchQueue.main.asyncAfter(deadline: deadline) {
dispatchPrecondition(condition: .onQueue(DispatchQueue.global()))
}