我已经阅读了苹果公司的iBook,但没有找到它的任何定义:
有人能解释一下dispatch_after
的结构吗?
dispatch_after(<#when: dispatch_time_t#>, <#queue: dispatch_queue_t?#>, <#block: dispatch_block_t?#>)
我已经阅读了苹果公司的iBook,但没有找到它的任何定义:
有人能解释一下dispatch_after
的结构吗?
dispatch_after(<#when: dispatch_time_t#>, <#queue: dispatch_queue_t?#>, <#block: dispatch_block_t?#>)
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
}
哇,一种可以提高编程语言的语言。有什么比这更好的吗?
现在他们改进了调用语法,似乎几乎不值得费事了:
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))) }
- Aviel Grossreturn
) 。 - matt1.0 ~~ { code...}
来实现。 - Yerk结构更清晰的概念:
dispatch_after(when: dispatch_time_t, queue: dispatch_queue_t, block: dispatch_block_t?)
dispatch_time_t
是一个 UInt64
。实际上, dispatch_queue_t
被类型别名为一个 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的非常好的delay
函数.
编辑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
枚举并只写一个数字,那么就假定您使用的是秒。
dispatch_after(1, dispatch_get_main_queue()) { println("test") }
- Billdispatch_after(1, ...)
中使用数字1
可能会引起很多混淆。人们会认为它是秒数,实际上它是纳秒。我建议查看@brindy的答案以了解如何正确创建这个数字。 - Hlung1
更改为 dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
,因为它容易引起混淆。人们可能会认为在Swift中不需要创建dispatch_time_t
。 - OemerAlet delayTime = DispatchTime.now() + .seconds(1.0)
上,它会抱怨二元运算符'+'不能将类型为DispatchTime和'_'的操作数应用于运算
。 - Andy IbanezDispatchTime.now() + 1.0
的写法似乎是让它正常工作的唯一方法(无需加上 .seconds
)。 - Andy IbanezSwift 3+
在Swift 3+中,这非常简单而优雅:
DispatchQueue.main.asyncAfter(deadline: .now() + 4.5) {
// ...
}
较早的答案:
对于 Cezary 的答案进行补充,如果想要在4.5秒后执行,我必须执行以下操作。
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,则隐式类型会导致编译错误。
如果有人能提出更优化的解决方案,我很乐意听取建议。
dispatch_get_main_queue()
替代了已弃用的API dispatch_get_current_queue()
,因此编译器出现错误。 - David Ldispatch_get_main_queue()
绝对是你应该使用的。我会更新的。 - brindy马特的语法非常好,如果您需要使块无效,您可能想要使用这个:
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)
}
上面的链接似乎已失效。 来自Github的原始Objc代码
performSelector:afterDelay:
现在可用,因此您可以取消它。 - mattdispatch_source_t
,因为您可以取消它)来补偿其损失。 - mattdelay(1.0) { cancel_delay(retVal) }
? - MikeGSwift 3.0、Swift 4.0 和 Swift 5.0 中最简单的解决方案
func delayWithSeconds(_ seconds: Double, completion: @escaping () -> ()) {
DispatchQueue.main.asyncAfter(deadline: .now() + seconds) {
completion()
}
}
使用方法
delayWithSeconds(1) {
//Do something
}
苹果公司为 Objective-C 提供了一个 dispatch_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)
})
我喜欢马特的延迟函数,但出于偏好,我宁愿限制传递闭包。
In Swift 3.0
Dispatch queues
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)
}
}
在视图控制器上调用此方法:
self.runAfterDelay(5.0, block: {
//Add code to this block
print("run After Delay Success")
})
performSelector("yourMethod Name", withObject: nil, afterDelay: 1)
override func viewWillAppear(animated: Bool) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2), dispatch_get_main_queue(), { () -> () in
//Code Here
})
//紧凑表单
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2), dispatch_get_main_queue()) {
//Code here
}
}
NSTimer
相关的问题已被标记为此问题的重复项,因此在此包括一个NSTimer
答案。
NSTimer
vs dispatch_after
NSTimer
更高层次,而dispatch_after
更低级。NSTimer
更容易取消。取消dispatch_after
需要编写更多代码。NSTimer
延迟任务创建一个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
. If you have a one time event with no need to cancel then there is no need to create the timer
instance variable. The following will suffice:
NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: #selector(delayedAction), userInfo: nil, repeats: false)
See my fuller answer here.