如何实现多个异步操作结束后执行后续动作
场景:我们可能对列表中的数据进行批量操作后,执行下一步操作。如多选删除后,刷新页面;如多选下载后,提示下载完成。
我们需要用到的一个核心的东西就是信号量:DispatchSemaphore
首先介绍下信号量
的基本语法
初始化
swift
let sema = DispatchSemaphore.init(value: 0)
oc
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
可以看出,我们传了一个 Int 值用于初始化信号量。
两个核心方法
swift
//等待
sema.wait()
//完成
sema.signal()
oc
//等待
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
//完成
dispatch_semaphore_signal(sema);
wait
会对信号量 -1, -1后,如果信号量<0,则会阻塞线程
signal
会对信号量 +1
接着让我们看下信号量
的简单用法
1、单任务实例
以 swift 为例
//1
DispatchQueue.global().async {
//2
let sema = DispatchSemaphore.init(value: 0)
//3
NetManager.shared().checkPermission(withSpace: model.spaceType, andParentID: parentId, andChildenID: [modid], andAction: "copyFile2All", success: { (result) in
//4
sema.signal()
}) { (msg) in
//4
sema.signal()
}
//5
sema.wait()
//6
}
代码解读:
- wait 方法会阻塞主线程,所以需要放在子线程中,本例放在 global 中
- 创建信号量对象,信号量为 0
- 网络请求的任务,使用的是AFNetworking
- 任务完成,信号量+1
- 信号量首先-1,然后检测信号的值。当信号量<0时阻塞,并一直检测信号量变化,直到信号量>0时,便会往后执行,
- 注意:使用信号量,一定要放在子线程中,否则主线程会一直阻塞。
如上所示,我们可以在 注释6
的位置写上我们需要执行的代码。便达到了通过信号量等待一个任务完成后,执行下一个任务的要求。
2、多任务实例
DispatchQueue.global().async {
let sema = DispatchSemaphore.init(value: 0)
for i in self.selectedItems {
NetManager.shared().checkPermission(withSpace: model.spaceType, andParentID: parentId, andChildenID: [modid], andAction: "copyFile2All", success: { (result) in
self.performSegue(withIdentifier: "showDirectoryTreevcID", sender: "copy")
sema.signal()
}) { (msg) in
//
sema.signal()
}
}
for _ in self.selectedItems {
sema.wait()
}
//刷新 UI 等操作可以放在这里(注:如果是对 UI 操作要放在主线程哦)
}
通过单任务实例
理解这个多任务的实例应该不难,在此不多做赘述。
总结
- 上例中的网络请求方法只是实例用的,读者可以自己写个网络请求替换掉
- 信号量有三个比较关键的点(信号量的值,wait 方法,signal 方法),理解透了用起来很简单,且好用
- 信号量的初始化的值在本例中为 0,如果是正整数,一般用于多任务线程池(比如同时最大支持n 个任务上传)。
网友评论