我如何dispatch_sync, dispatch_async, dispatch_after等在Swift 3, Swift 4,和超越?

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

或任何其他类型的大中央调度API的使用…

现在我已经在Xcode 8(测试版)中为Swift 3打开了我的项目,我得到了各种各样的错误。他们中的一些人愿意修复我的代码,但并不是所有的修复都能产生工作代码。我该怎么办?

209699 次浏览

从一开始,Swift就提供了一些使ObjC和C更Swifty的功能,每个版本都增加了更多功能。现在,在Swift 3中,新的导入为成员特性让具有某些C API风格的框架更像Swift原生API——其中你有一个工作起来有点像类的数据类型,以及一堆全局函数。数据类型作为Swift类导入,它们相关的全局函数作为这些类的方法和属性导入,一些相关的东西,如常量集,可以在适当的地方成为子类型。

在Xcode 8 / Swift 3测试版中,苹果应用了这个功能(以及其他一些功能),使Dispatch框架更加Swifty。(还有核心图形。)如果你一直在关注Swift开源的努力,这不是新闻,但现在是它第一次成为Xcode的一部分。

将任何项目迁移到Swift 3的第一步应该是在Xcode 8中打开它,并在菜单中选择编辑>转换>到当前Swift语法…。这将应用(在您的审查和批准下)所有重命名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的关于背景工作和能源效率的文件

顺便说一下,如果你保持自己的队列来组织工作,现在获取一个队列的方式是这样的(注意DispatchQueueAttributesOptionSet,所以你使用集合风格的字面量来组合选项):

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 8中打开它的接口来找到新的Dispatch API——使用“快速打开”来找到Dispatch模块,或者在你的Swift项目/操场上放一个符号(比如DispatchQueue),然后命令点击它,然后从那里浏览模块。(你可以在苹果漂亮的新API参考网站和xcode文档查看器中找到Swift 调度 API,但看起来C版本的文档内容还没有移动到它里面。)

更多提示请参见迁移向导

在Xcode 8 beta 4不工作…

使用:

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
print("Are we there yet?")
}

对于async有两种方式:

DispatchQueue.main.async {
print("Async1")
}


DispatchQueue.main.async( execute: {
print("Async2")
})

在Xcode 8中使用:

DispatchQueue.global(qos: .userInitiated).async { }

这是关于asyncSwift 4的一个很好的例子:

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类。如果不想使用Threads类,可以从类方法中复制所需的队列代码。

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