dispatch_after – GCD在swift中?

我已经通过了苹果的iBook ,并找不到它的任何定义:

有人可以解释dispatch_after的结构吗?

 dispatch_after(<#when: dispatch_time_t#>, <#queue: dispatch_queue_t?#>, <#block: dispatch_block_t?#>) 

对结构更清晰的概念:

 dispatch_after(when: dispatch_time_t, queue: dispatch_queue_t, block: dispatch_block_t?) 

dispatch_time_t是一个UInt64dispatch_queue_t实际上是一个types别名到一个NSObject ,但你应该使用你熟悉的GCD方法来获得队列。 该块是一个Swift结束。 具体来说, dispatch_block_t定义为() -> Void ,相当于() -> ()

用法示例:

 let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC))) dispatch_after(delayTime, dispatch_get_main_queue()) { print("test") } 

编辑:

我推荐使用@ matt的非常好的delayfunction 。

编辑2:

在Swift 3中,GCD将会有新的包装。 看到这里: https : //github.com/apple/swift-evolution/blob/master/proposals/0088-libdispatch-for-swift3.md

在Swift 3中,最初的例子将写成如下:

 let deadlineTime = DispatchTime.now() + .seconds(1) DispatchQueue.main.asyncAfter(deadline: deadlineTime) { print("test") } 

请注意,您可以将deadlineTime声明写为DispatchTime.now() + 1.0并获得相同的结果,因为+操作符被覆盖如下(类似于- ):

  • func +(time: DispatchTime, seconds: Double) -> DispatchTime
  • func +(time: DispatchWalltime, interval: DispatchTimeInterval) -> DispatchWalltime

这意味着如果您不使用DispatchTimeInterval enum并只写一个数字,则假定您正在使用秒。

我经常使用dispatch_after所以我编写了一个顶级的实用程序函数来简化语法:

 func delay(delay:Double, closure:()->()) { dispatch_after( dispatch_time( DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)) ), dispatch_get_main_queue(), closure) } 

现在你可以这样说话了:

 delay(0.4) { // do stuff } 

哇,一种可以改善语言的语言。 有什么更好的?


更新Swift 3,Xcode 8 Seed 6

似乎几乎不值得打扰,现在他们已经改进了调用语法:

 func delay(_ delay:Double, closure:@escaping ()->()) { let when = DispatchTime.now() + delay DispatchQueue.main.asyncAfter(deadline: when, execute: closure) } 

马特的语法是非常好的,如果你需要使块无效,你可能想要使用这个:

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

使用如下

 let retVal = delay(2.0) { println("Later") } delay(1.0) { cancel_delay(retVal) } 

学分

上面的链接似乎是closures的。 来自Github的原始Objc代码

为了扩大Cezary的答案,在1纳秒后执行,我必须在4秒半之后执行以下操作。

  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) 

编辑:我发现我的原代码有点不对。 如果不将NSEC_PER_SEC转换为Double,则隐式键入会导致编译错误。

如果有人可以提出一个更优化的解决scheme,我会热衷于听到它。

==更新Swift 3 ==

这在Swift 3中是超级简单而优雅的:

  DispatchQueue.main.asyncAfter(deadline: .now() + 4.5) { // ... } 

苹果有一个Objective-Cdispatch_after片段

 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#> }); 

这里是与Swift 3相同的代码片段:

 DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + <#delayInSeconds#>) { <#code to be executed after a specified delay#> } 

另一种方法是像这样扩展Double:

 extension Double { var dispatchTime: dispatch_time_t { get { return dispatch_time(DISPATCH_TIME_NOW,Int64(self * Double(NSEC_PER_SEC))) } } } 

那么你可以像这样使用它:

 dispatch_after(Double(2.0).dispatchTime, dispatch_get_main_queue(), { () -> Void in self.dismissViewControllerAnimated(true, completion: nil) }) 

我喜欢马特的延迟function,但只是偏好我宁愿限制周围的封闭。

Swift 3.0和Swift 4.0中最简单的解决scheme

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

用法

 delayWithSeconds(1) { //Do something } 

在Swift 3.0中

调度队列

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

5秒后发送

  DispatchQueue.main.after(when: DispatchTime.now() + 5) { print("Dispatch after 5 sec") } 

1)添加这个方法作为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) } } 

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

//紧凑forms

 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2), dispatch_get_main_queue()) { //Code here } 

}

Swift 3.0版本

在closuresfunction之后,在主线程上执行一些任务。

 func performAfterDelay(delay : Double, onCompletion: @escaping() -> Void){ DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delay, execute: { onCompletion() }) } 

像这样调用这个函数:

 performAfterDelay(delay: 4.0) { print("test") } 

虽然不是OP的原始问题,但某些与NSTimer相关的问题已经被标记为这个问题的重复,所以在这里值得包含NSTimer答案。

NSTimer vs dispatch_after

  • NSTimerdispatch_after更高级别,更低级别。
  • NSTimer更容易取消。 取消dispatch_after需要编写更多的代码 。

NSTimer延迟任务

创build一个NSTimer实例。

 var timer = NSTimer() 

以所需的延迟启动计时器。

 // 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) 

添加一个延迟后调用的函数(使用上面selector参数的任何名称)。

 func delayedAction() { print("Delayed action has now started." } 

笔记

  • 如果您在动作发生之前需要取消动作,只需调用timer.invalidate()
  • 对于重复的动作repeats: true使用repeats: true
  • 如果您有一次性事件而不需要取消,则不需要创buildtimer实例variables。 以下就足够了:

     NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: #selector(delayedAction), userInfo: nil, repeats: false) 
  • 在这里看到我更完整的答案。

另一个帮助你延迟使用100%Swift的代码,还可以select不同的线程来运行你的延迟代码:

 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) { // delayed code } 

如果你想延迟你的代码到不同的线程

 delay(bySeconds: 1.5, dispatchLevel: .background) { // delayed code that will run on background thread } 

如果你更喜欢一个框架 ,也有一些更方便的function,然后检查HandySwift 。 您可以通过Carthage将其添加到您的项目中然后像上面的示例中那样使用它,例如:

 import HandySwift delay(bySeconds: 1.5) { // delayed code } 

这对我有效。

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

2.0秒后使用此代码执行一些与UI相关的任务。

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

Swift 3.0版本

在closuresfunction之后,在主线程上执行一些任务。

 func performAfterDelay(delay : Double, onCompletion: @escaping() -> Void){ DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delay, execute: { onCompletion() }) } 

像这样调用这个函数:

 performAfterDelay(delay: 4.0) { print("test") }