dispatch_after - GCD in Swift?
我查过苹果的iBook,找不到它的任何定义:
有人能解释一下
1 | dispatch_after(<#when: dispatch_time_t#>, <#queue: dispatch_queue_t?#>, <#block: dispatch_block_t?#>) |
我经常使用
1 2 3 4 5 6 7 8 | func delay(delay:Double, closure:()->()) { dispatch_after( dispatch_time( DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)) ), dispatch_get_main_queue(), closure) } |
现在你可以这样说:
1 2 3 | delay(0.4) { // do stuff } |
哇,一种你可以改进语言的语言。还有什么更好的呢?
更新swift 3,xcode 8 seed 6似乎不值得费心,因为他们已经改进了调用语法:
1 2 3 4 | func delay(_ delay:Double, closure:@escaping ()->()) { let when = DispatchTime.now() + delay DispatchQueue.main.asyncAfter(deadline: when, execute: closure) } |
更清晰的结构概念:
1 | dispatch_after(when: dispatch_time_t, queue: dispatch_queue_t, block: dispatch_block_t?) |
示例用法:
1 2 3 4 | let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC))) dispatch_after(delayTime, dispatch_get_main_queue()) { print("test") } |
编辑:
我建议使用@matt非常好的
编辑2:
在Swift 3中,将为GCD提供新包装。请参见:https://github.com/apple/swift-evolution/blob/master/proposals/0088-libdispatch-for-swift3.md
原始示例将在swift 3中编写如下:
1 2 3 4 | let deadlineTime = DispatchTime.now() + .seconds(1) DispatchQueue.main.asyncAfter(deadline: deadlineTime) { print("test") } |
请注意,您可以将
func +(time: DispatchTime, seconds: Double) -> DispatchTime func +(time: DispatchWalltime, interval: DispatchTimeInterval) -> DispatchWalltime
这意味着,如果您不使用
为了扩展Cezary的答案,它将在1纳秒后执行,我必须在4.5秒后执行以下操作。
1 2 3 | 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,隐式键入将导致编译错误。
如果有人能提出一个更理想的解决方案,我会很乐意听到。
==更新swift 3==
这在Swift 3中非常简单和优雅:
1 2 3 | DispatchQueue.main.asyncAfter(deadline: .now() + 4.5) { // ... } |
Matt的语法非常好,如果需要使块无效,可以使用以下方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | 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) } } |
使用如下
1 2 3 4 5 6 | let retVal = delay(2.0) { println("Later") } delay(1.0) { cancel_delay(retVal) } |
信用
上面的链接似乎已断开。来自Github的原始objc代码
苹果有一个针对Objective-C的一段接一段的调度:
1 2 3 | 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的相同代码段:
1 2 3 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + <#delayInSeconds#>) { <#code to be executed after a specified delay#> } |
Swift 3.0和Swift 4.0中最简单的解决方案
1 2 3 4 5 | func delayWithSeconds(_ seconds: Double, completion: @escaping () -> ()) { DispatchQueue.main.asyncAfter(deadline: .now() + seconds) { completion() } } |
用法
1 2 3 | delayWithSeconds(1) { //Do something } |
另一种方法是像这样扩展双精度:
1 2 3 4 5 6 7 | extension Double { var dispatchTime: dispatch_time_t { get { return dispatch_time(DISPATCH_TIME_NOW,Int64(self * Double(NSEC_PER_SEC))) } } } |
然后你可以这样使用它:
1 2 3 | dispatch_after(Double(2.0).dispatchTime, dispatch_get_main_queue(), { () -> Void in self.dismissViewControllerAnimated(true, completion: nil) }) |
我喜欢Matt的延迟函数,但出于偏好,我宁愿限制传递闭包。
在斯威夫特3
调度队列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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秒后发送
1 2 3 | DispatchQueue.main.after(when: DispatchTime.now() + 5) { print("Dispatch after 5 sec") } |
Swift 3.0版本
在关闭函数之后,在主线程上延迟之后执行一些任务。
1 2 3 4 5 6 | func performAfterDelay(delay : Double, onCompletion: @escaping() -> Void){ DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delay, execute: { onCompletion() }) } |
调用此函数的方式如下:
1 2 3 | performAfterDelay(delay: 4.0) { print("test") } |
1)将此方法添加为uiviewcontroller扩展的一部分。
1 2 3 4 5 6 | 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上调用此方法:
1 2 3 4 | self.runAfterDelay(5.0, block: { //Add code to this block print("run After Delay Success") }) |
2)
1 | performSelector("yourMethod Name", withObject: nil, afterDelay: 1) |
3)
1 2 3 4 5 | override func viewWillAppear(animated: Bool) { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2), dispatch_get_main_queue(), { () -> () in //Code Here }) |
/紧凑型
1 2 3 4 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2), dispatch_get_main_queue()) { //Code here } } |
虽然不是OP提出的原始问题,但某些与
NSTimer 的水平较高,而dispatch_after 的水平较低。NSTimer 更容易取消。取消dispatch_after 需要编写更多的代码。
用
创建一个
1 | var timer = NSTimer() |
用你需要的延迟启动计时器。
1 2 3 4 | // 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) |
添加要在延迟后调用的函数(使用上面用于
1 2 3 | func delayedAction() { print("Delayed action has now started." } |
笔记
- 如果您需要在操作发生之前取消操作,只需致电
timer.invalidate() 。 - 重复动作使用
repeats: true 。 如果有一个一次性事件不需要取消,那么就不需要创建
timer 实例变量。以下内容就足够了:1NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: #selector(delayedAction), userInfo: nil, repeats: false)看我更完整的答案。
Swift 3和4:
您可以在DispatchQueue上创建扩展,并添加在内部使用DispatchQueue AsyncAfter函数的函数延迟
1 2 3 4 5 6 | extension DispatchQueue { static func delay(_ delay: DispatchTimeInterval, closure: @escaping () -> ()) { let timeInterval = DispatchTime.now() + delay DispatchQueue.main.asyncAfter(deadline: timeInterval, execute: closure) } } |
用途:
1 2 3 | DispatchQueue.delay(.seconds(1)) { print("This is after delay") } |
对于多个函数,请使用此选项。这对于静态函数或任何UI更新使用动画或活动加载器非常有用。
1 2 3 4 5 6 | DispatchQueue.main.asyncAfter(deadline: .now() + 0.9) { // Call your function 1 DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { // Call your function 2 } } |
例如-在重新加载TableView之前使用动画。或动画后的任何其他用户界面更新。
1 2 3 4 5 6 7 8 9 10 11 | *// 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() } } |
这对我很有用。
斯威夫特3:
1 2 3 4 5 6 7 8 | let time1 = 8.23 let time2 = 3.42 // Delay 2 seconds DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { print("Sum of times: \(time1 + time2)") } |
ObjultC:
1 2 3 4 5 6 7 8 9 | 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); }); |
在斯威夫特4
使用此代码段:
1 2 3 4 5 | let delayInSec = 1.0 DispatchQueue.main.asyncAfter(deadline: .now() + delayInSec) { // code here print("It works") } |
我总是喜欢使用扩展而不是自由函数。
斯威夫特4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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() } } } |
使用如下。
1 2 3 | DispatchQueue.performAction(after: 0.3) { // Code Here } |
在swift中使用asyncAfter延迟gcd调用
1 2 | let delayQueue = DispatchQueue(label:"com.theappmaker.in", qos: .userInitiated) let additionalTime: DispatchTimeInterval = .seconds(2) |
我们可以延迟**微秒、毫秒、纳秒
1 2 3 4 5 6 7 | delayQueue.asyncAfter(deadline: .now() + 0.60) { print(Date()) } delayQueue.asyncAfter(deadline: .now() + additionalTime) { print(Date()) } |
1 2 3 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // ... }); |
a delay
a dispatch queue
a block or closure
我建议学习Raywenderlich调度教程
另一个帮助程序可以延迟您的代码,该代码的使用速度为100%,并且可以选择其他线程来运行您的延迟代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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) } } } |
现在您只需在主线程上延迟代码,如下所示:
1 2 3 | delay(bySeconds: 1.5) { // delayed code } |
如果要将代码延迟到其他线程:
1 2 3 | delay(bySeconds: 1.5, dispatchLevel: .background) { // delayed code that will run on background thread } |
如果您喜欢一个框架,它也有一些更方便的特性,那么签出handyswift。您可以通过迦太基将其添加到您的项目中,然后像上面的示例一样使用它,例如:
1 2 3 4 5 | import HandySwift delay(bySeconds: 1.5) { // delayed code } |
现在,在Swift的Grand Central Dispatch(GCD)中,异步调度的语法范围已经超过了。
添加PoD文件
1 | pod 'AsyncSwift' |
然后,你可以这样使用它。
1 2 3 4 5 6 | 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") } |
使用此代码在2.0秒后执行一些与UI相关的任务。
1 2 3 4 5 6 7 8 | 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版本
在关闭函数之后,在主线程上延迟之后执行一些任务。
1 2 3 4 5 6 | func performAfterDelay(delay : Double, onCompletion: @escaping() -> Void){ DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delay, execute: { onCompletion() }) } |
调用此函数的方式如下:
1 2 3 | performAfterDelay(delay: 4.0) { print("test") } |
Swift 4的方法很短:
1 2 3 4 | Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { (timer) in // Your stuff here print("hello") } |