Dispatch之后:Swift中的GCD 3、4和5示例

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

如何不再害怕延迟并爱上Swift 3、4和5中的GCD

\n\n

你是否曾经写过一段代码,本应在三秒后执行,却立即触发了?或者相反,你等了很久,明明只计划了几毫秒?熟悉吗?那你一定遇到过dispatch_after——这是Grand Central Dispatch (GCD)中最流行但也是最棘手的工具之一。

\n\n

以前,在Swift 2和Objective-C时代,这个方法看起来像咒语:dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(nanoseconds)), dispatch_get_main_queue())。但随着Swift 3、4和5的到来,GCD的API被完全重写了。现在这不仅仅是名称的改变——这是一种全新的思维方式。在本文中,我们将探讨如何在所有当前版本中编写Swift中的dispatch_after,破除迷思,并提供现成的解决方案。开始吧!

\n\n

dispatch_after发生了什么?一段简短的痛苦历史

\n

在Swift 3之前,开发者使用C风格的GCD:

\n
let delay = dispatch_time(DISPATCH_TIME_NOW, Int64(2.0 * Double(NSEC_PER_SEC)))\ndispatch_after(delay, dispatch_get_main_queue()) {\n    print("来自过去的问候!")\n}
\n

这虽然有效,但看起来很笨重。在Swift 3中,Apple决定将GCD“Swift化”,将其转变为面向对象的API。现在dispatch_after变成了DispatchQueue结构体的方法asyncAfter。这不仅仅是表面上的修整——这是一个需要理解的全新语法。

\n\n

基本配方:Swift 3、4和5中的asyncAfter

\n

无论Swift版本(3、4或5),dispatch_after的基本语法现在看起来都一样。以下是在主线程上延迟执行的最简单示例:

\n\n
let delayInSeconds: Double = 2.0\nDispatchQueue.main.asyncAfter(deadline: .now() + delayInSeconds) {\n    print("2秒过去了!")\n}
\n

关键点:

\n
    \n
  • DispatchQueue.main — 主线程(UI)。
  • \n
  • .now() + delayInSeconds — 创建相对于当前时刻的截止时间(deadline)。
  • \n
  • asyncAfter — 在指定时间后异步执行。
  • \n
\n

这段代码在Swift 3.0、4.0和5.0中无需修改即可运行。神奇之处在于,Apple自2016年以来一直保持这个API的稳定。

\n\n

那dispatch_time呢?处理纳秒

\n

有时你需要以纳秒为单位指定延迟(例如,用于精确计时器或游戏逻辑)。在新API中,使用DispatchTime:

\n
let nanoseconds: Int = 1_500_000_000 // 1.5秒\nlet deadline = DispatchTime.now() + .nanoseconds(nanoseconds)\nDispatchQueue.global().asyncAfter(deadline: deadline) {\n    print("1.5秒后在后台线程执行")\n}
\n

你还可以使用现成的常量:.seconds(5)、.milliseconds(500),甚至.microseconds(1000)。这比乘以NSEC_PER_SEC更方便。

\n\n

关于Swift中dispatch_after的常见问题(和答案!)

\n

在Stack Overflow上,这个问题已经积累了数千次浏览。以下是新手最容易踩的坑。

\n\n

1. 为什么我的代码立即执行,而不是延迟执行?

\n

最常见的错误是混淆asyncAfter和async。如果你忘记指定deadline:,或者写了DispatchQueue.main.async { ... },代码会立即执行。第二个原因是传递了负值。.now() + (-5.0)表示过去的时间,GCD会立即执行该块。

\n\n

2. 如何取消dispatch_after?

\n

与Timer不同,asyncAfter没有内置的cancel()方法。但有两种解决方案:

\n
    \n
  • 取消标志:使用Dispatc

博客

书籍推荐