如何知道iOS多个异步任务执行完成的回调通知
2017-12-03 本文已影响16人
轰炸机上调鸡尾酒
项目遇到一个问题,一个页面有两个接口,需要知道两个网络请求都成功后再去更新UI。网络请求是异步的,如何检测两个网络请求都请求结束呢。
这个时候信号量就派上用场了。
信号量是一种计数器,如果方法中设置了一个信号量,当它大于0,方法会按正常模式往下执行,如果等于0则会阻塞住,直到它大于0时,就会往下执行了。
////创建一个信号量,初始值为0
let semaphore = DispatchSemaphore.init(value: 0)
//等待信号,信号量减1,如果信号量小于0,方法会阻塞住。
semaphore.wait()
//发送一个信号,信号量加1
semaphore.signal()
DispatchSemaphore.init(value: 0)传入的参数为lnt,输出一个DispatchSemaphore的对象。值得注意的是,这里的传入的参数value必须大于或等于0。
semaphore.wait()这个函数会使传入的信号量的值减1。这个函数的作用是这样的,如果信号量的值大于0,该函数所处线程就继续执行下面的语句,并且将信号量的值减1;如果信号量的值为0,那么这个函数就阻塞当前线程等待timeout。
好了开始进入正题,如果在多个网络请求完成后得到这个消息的回调。信号量在这里就立功了。当然我们还要结合使用下线程组。
注意
因为网络请求是异步的。线程组里任务需要提前进入我们创建的并行队列中。
override func viewDidLoad() {
super.viewDidLoad()
fetchPreInfo()
isShowDraftView()
//用全局队列来接受线程组的任务回调
let defaultQueue = DispatchQueue.global()
group.notify(queue: defaultQueue) {
print("Done")
}
}
fileprivate let group = DispatchGroup()
fileprivate let queue = DispatchQueue(label: "create.diary", attributes: .concurrent)
// MARK: - 这个方法是请求是否展示草稿
func isShowDraftView() {
//将任务1异步提交到queue中
queue.async(group: group) {
//对于这个异步的网络请求任务1,我们使用信号量使其同步化
let semaphore = DispatchSemaphore(value: 0)
self.hasDraftView(["type": "1", "diary_id": String(self.diaryId)]) { [weak self](hasDraft, error, _) in
//网络请求有结果之后(无论成功还是失败)信号量+1,标识这任务1已经完成
semaphore.signal()
print("是否展示草稿接口请求完成")
}
//这里wait函数设置下超时等待时间,如果超过30秒,我们认为网络请求超时失败了。
_ = semaphore.wait(timeout: DispatchTime.now() + 30)
}
}
// MARK: - 这个方法获取发日记贴前的预置信息
func fetchPreInfo() {
//将任务2异步提交到queue中
queue.async(group: group) {
//对于这个异步的网络请求任务2,我们也使用信号量使其同步化
let semaphore = DispatchSemaphore(value: 0)
self.viewModel.fetchPreInfo (["diary_id": self.diaryId]) { [weak self] (data, error, _) in
//网络请求有结果之后(无论成功还是失败)信号量+1,标识这任务1已经完成
semaphore.signal()
print("获取发日记贴前的预置信接口请求完成")
}
// 在网络请求任务成功之前,信号量等待中
_ = semaphore.wait(timeout: DispatchTime.now() + 30)
}
}
这样我们就可以检测到两个任务都完成之后,然后回到主线程做一个UI或者其他的操作。完美!