我如何 dispatch_sync、dispatch_async、dispatch_after 等 Swift 3、Swift 4 及以后?
How do I dispatch_sync, dispatch_async, dispatch_after, etc in Swift 3, Swift 4, and beyond?
我在 Swift 2.x(甚至 1.x)项目中有很多代码如下所示:
// Move to a background thread to do some long running work
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
let image = self.loadOrGenerateAnImage()
// Bounce back to the main thread to update the UI
dispatch_async(dispatch_get_main_queue()) {
self.imageView.image = image
}
}
或者像这样延迟执行的东西:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.5 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
print("test")
}
或 Grand Central Dispatch 的任何其他用途 API...
现在我已经在 Xcode 8(测试版)中为 Swift 3 打开了我的项目,我遇到了各种错误。他们中的一些人提出修复我的代码,但并非所有修复都会产生工作代码。我该怎么办?
从一开始,Swift 就提供了一些使 ObjC 和 C 更 Swifty 的工具,每个版本都添加了更多。现在,在 Swift 3 中,新的 "import as member" 特性允许框架具有某些 C API 风格——您的数据类型有点像 class,和一堆全局函数来处理它——更像 Swift-native APIs。数据类型作为 Swift classes 导入,它们相关的全局函数作为那些 classes 上的方法和属性导入,一些相关的东西,如常量集,可以在适当的时候成为子类型。
在 Xcode 8 / Swift 3 beta 中,Apple 应用了此功能(以及其他一些功能),使 Dispatch 框架更加 Swifty。 (还有 Core Graphics, too.) If you've been following the Swift open-source efforts, this isn't news,但现在是它第一次成为 Xcode 的一部分。
将任何项目移动到 Swift3 的第一步应该是在 Xcode8 中打开它并选择 编辑 >菜单中的 Convert > To Current Swift Syntax...。这将立即应用(在您的审查和批准下)所有重命名的 API 和其他更改所需的所有更改。 (通常,一行代码同时受到多个更改的影响,因此单独响应错误修复可能无法正确处理所有问题。)
结果是,将工作弹回后台并返回的常见模式现在如下所示:
// Move to a background thread to do some long running work
DispatchQueue.global(qos: .userInitiated).async {
let image = self.loadOrGenerateAnImage()
// Bounce back to the main thread to update the UI
DispatchQueue.main.async {
self.imageView.image = image
}
}
请注意,我们使用 .userInitiated
而不是旧的 DISPATCH_QUEUE_PRIORITY
常量之一。 OS X 10.10 / iOS 8.0 中引入了服务质量 (QoS) 说明符,为系统确定工作优先级提供了更清晰的方式,并弃用了旧的优先级说明符。有关详细信息,请参阅 Apple docs on background work and energy efficiency。
顺便说一下,如果您保留自己的队列来组织工作,现在获取队列的方法如下所示(注意 DispatchQueueAttributes
是一个 OptionSet
,因此您使用集合-style 文字组合选项):
class Foo {
let queue = DispatchQueue(label: "com.example.my-serial-queue",
attributes: [.serial, .qosUtility])
func doStuff() {
queue.async {
print("Hello World")
}
}
}
以后用dispatch_after
工作?这也是队列上的一种方法,它需要一个 DispatchTime
,它具有用于各种数字类型的运算符,因此您可以只添加整数秒或小数秒:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { // in half a second...
print("Are we there yet?")
}
您可以通过在 Xcode 中打开其界面来找到新的 Dispatch API 8 -- 使用“快速打开”找到 Dispatch 模块,或放置一个符号(如 DispatchQueue
) 在你的 Swift project/playground 中并按住命令单击它,然后从那里浏览模块。 (您可以在 Apple 漂亮的新 API 参考网站和 Xcode 文档查看器中找到 Swift Dispatch API,但它看起来像是来自C 版本还没有进入它。)
有关更多提示,请参阅 Migration Guide。
在 Xcode 8 beta 4 中不起作用...
使用:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
print("Are we there yet?")
}
异步两种方式:
DispatchQueue.main.async {
print("Async1")
}
DispatchQueue.main.async( execute: {
print("Async2")
})
在Xcode8中使用:
DispatchQueue.global(qos: .userInitiated).async { }
这个是 Swift 4
关于 async
:
的好例子
DispatchQueue.global(qos: .background).async {
// Background Thread
DispatchQueue.main.async {
// Run UI Updates or call completion block
}
}
Swift 5.2、4 及更高版本
主队列和后台队列
let main = DispatchQueue.main
let background = DispatchQueue.global()
let helper = DispatchQueue(label: "another_thread")
使用异步和同步线程!
background.async { //async tasks here }
background.sync { //sync tasks here }
异步线程将与主线程一起工作。
同步线程在执行时会阻塞主线程。
Swift 4.1 和 5. 我们在代码中的很多地方都使用了队列。因此,我创建了包含所有队列的 Threads class。如果您不想使用线程 class,您可以从 class 方法中复制所需的队列代码。
class Threads {
static let concurrentQueue = DispatchQueue(label: "AppNameConcurrentQueue", attributes: .concurrent)
static let serialQueue = DispatchQueue(label: "AppNameSerialQueue")
// Main Queue
class func performTaskInMainQueue(task: @escaping ()->()) {
DispatchQueue.main.async {
task()
}
}
// Background Queue
class func performTaskInBackground(task:@escaping () throws -> ()) {
DispatchQueue.global(qos: .background).async {
do {
try task()
} catch let error as NSError {
print("error in background thread:\(error.localizedDescription)")
}
}
}
// Concurrent Queue
class func perfromTaskInConcurrentQueue(task:@escaping () throws -> ()) {
concurrentQueue.async {
do {
try task()
} catch let error as NSError {
print("error in Concurrent Queue:\(error.localizedDescription)")
}
}
}
// Serial Queue
class func perfromTaskInSerialQueue(task:@escaping () throws -> ()) {
serialQueue.async {
do {
try task()
} catch let error as NSError {
print("error in Serial Queue:\(error.localizedDescription)")
}
}
}
// Perform task afterDelay
class func performTaskAfterDealy(_ timeInteval: TimeInterval, _ task:@escaping () -> ()) {
DispatchQueue.main.asyncAfter(deadline: (.now() + timeInteval)) {
task()
}
}
}
显示主队列使用的示例。
override func viewDidLoad() {
super.viewDidLoad()
Threads.performTaskInMainQueue {
//Update UI
}
}
我在 Swift 2.x(甚至 1.x)项目中有很多代码如下所示:
// Move to a background thread to do some long running work
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
let image = self.loadOrGenerateAnImage()
// Bounce back to the main thread to update the UI
dispatch_async(dispatch_get_main_queue()) {
self.imageView.image = image
}
}
或者像这样延迟执行的东西:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.5 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
print("test")
}
或 Grand Central Dispatch 的任何其他用途 API...
现在我已经在 Xcode 8(测试版)中为 Swift 3 打开了我的项目,我遇到了各种错误。他们中的一些人提出修复我的代码,但并非所有修复都会产生工作代码。我该怎么办?
从一开始,Swift 就提供了一些使 ObjC 和 C 更 Swifty 的工具,每个版本都添加了更多。现在,在 Swift 3 中,新的 "import as member" 特性允许框架具有某些 C API 风格——您的数据类型有点像 class,和一堆全局函数来处理它——更像 Swift-native APIs。数据类型作为 Swift classes 导入,它们相关的全局函数作为那些 classes 上的方法和属性导入,一些相关的东西,如常量集,可以在适当的时候成为子类型。
在 Xcode 8 / Swift 3 beta 中,Apple 应用了此功能(以及其他一些功能),使 Dispatch 框架更加 Swifty。 (还有 Core Graphics, too.) If you've been following the Swift open-source efforts, this isn't news,但现在是它第一次成为 Xcode 的一部分。
将任何项目移动到 Swift3 的第一步应该是在 Xcode8 中打开它并选择 编辑 >菜单中的 Convert > To Current Swift Syntax...。这将立即应用(在您的审查和批准下)所有重命名的 API 和其他更改所需的所有更改。 (通常,一行代码同时受到多个更改的影响,因此单独响应错误修复可能无法正确处理所有问题。)
结果是,将工作弹回后台并返回的常见模式现在如下所示:
// Move to a background thread to do some long running work
DispatchQueue.global(qos: .userInitiated).async {
let image = self.loadOrGenerateAnImage()
// Bounce back to the main thread to update the UI
DispatchQueue.main.async {
self.imageView.image = image
}
}
请注意,我们使用 .userInitiated
而不是旧的 DISPATCH_QUEUE_PRIORITY
常量之一。 OS X 10.10 / iOS 8.0 中引入了服务质量 (QoS) 说明符,为系统确定工作优先级提供了更清晰的方式,并弃用了旧的优先级说明符。有关详细信息,请参阅 Apple docs on background work and energy efficiency。
顺便说一下,如果您保留自己的队列来组织工作,现在获取队列的方法如下所示(注意 DispatchQueueAttributes
是一个 OptionSet
,因此您使用集合-style 文字组合选项):
class Foo {
let queue = DispatchQueue(label: "com.example.my-serial-queue",
attributes: [.serial, .qosUtility])
func doStuff() {
queue.async {
print("Hello World")
}
}
}
以后用dispatch_after
工作?这也是队列上的一种方法,它需要一个 DispatchTime
,它具有用于各种数字类型的运算符,因此您可以只添加整数秒或小数秒:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { // in half a second...
print("Are we there yet?")
}
您可以通过在 Xcode 中打开其界面来找到新的 Dispatch API 8 -- 使用“快速打开”找到 Dispatch 模块,或放置一个符号(如 DispatchQueue
) 在你的 Swift project/playground 中并按住命令单击它,然后从那里浏览模块。 (您可以在 Apple 漂亮的新 API 参考网站和 Xcode 文档查看器中找到 Swift Dispatch API,但它看起来像是来自C 版本还没有进入它。)
有关更多提示,请参阅 Migration Guide。
在 Xcode 8 beta 4 中不起作用...
使用:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
print("Are we there yet?")
}
异步两种方式:
DispatchQueue.main.async {
print("Async1")
}
DispatchQueue.main.async( execute: {
print("Async2")
})
在Xcode8中使用:
DispatchQueue.global(qos: .userInitiated).async { }
这个是 Swift 4
关于 async
:
DispatchQueue.global(qos: .background).async {
// Background Thread
DispatchQueue.main.async {
// Run UI Updates or call completion block
}
}
Swift 5.2、4 及更高版本
主队列和后台队列
let main = DispatchQueue.main
let background = DispatchQueue.global()
let helper = DispatchQueue(label: "another_thread")
使用异步和同步线程!
background.async { //async tasks here }
background.sync { //sync tasks here }
异步线程将与主线程一起工作。
同步线程在执行时会阻塞主线程。
Swift 4.1 和 5. 我们在代码中的很多地方都使用了队列。因此,我创建了包含所有队列的 Threads class。如果您不想使用线程 class,您可以从 class 方法中复制所需的队列代码。
class Threads {
static let concurrentQueue = DispatchQueue(label: "AppNameConcurrentQueue", attributes: .concurrent)
static let serialQueue = DispatchQueue(label: "AppNameSerialQueue")
// Main Queue
class func performTaskInMainQueue(task: @escaping ()->()) {
DispatchQueue.main.async {
task()
}
}
// Background Queue
class func performTaskInBackground(task:@escaping () throws -> ()) {
DispatchQueue.global(qos: .background).async {
do {
try task()
} catch let error as NSError {
print("error in background thread:\(error.localizedDescription)")
}
}
}
// Concurrent Queue
class func perfromTaskInConcurrentQueue(task:@escaping () throws -> ()) {
concurrentQueue.async {
do {
try task()
} catch let error as NSError {
print("error in Concurrent Queue:\(error.localizedDescription)")
}
}
}
// Serial Queue
class func perfromTaskInSerialQueue(task:@escaping () throws -> ()) {
serialQueue.async {
do {
try task()
} catch let error as NSError {
print("error in Serial Queue:\(error.localizedDescription)")
}
}
}
// Perform task afterDelay
class func performTaskAfterDealy(_ timeInteval: TimeInterval, _ task:@escaping () -> ()) {
DispatchQueue.main.asyncAfter(deadline: (.now() + timeInteval)) {
task()
}
}
}
显示主队列使用的示例。
override func viewDidLoad() {
super.viewDidLoad()
Threads.performTaskInMainQueue {
//Update UI
}
}