题
gcd如何知道异步任务(例如网络任务)何时完成?我应该为此目的使用dispatch_retain和dispatch_release吗?更新:我不能用ARC调用这些方法中的任何一个……怎么办?
细节
我正在与进行大量网络访问的第三方库进行交互.我通过一个小类创建了一个包装器,它基本上提供了我需要的第三方类的所有方法,但是将调用包装在dispatch_async(serialQueue){() – >中. Void in(其中serialQueue是我的包装类的成员).
我试图确保每个对底层库的调用在下一次开始之前完成(某种程度上,它尚未在库中实现).
解决方法
重要的是,闭包可能已经启动的任何其他异步任务可能仍在运行(或者甚至可能尚未开始运行),但不考虑它们.
例如,对于以下代码:
dispatch_async(serialQueue) { print("Start") dispatch_async(backgroundQueue) { functionThatTakes10Seconds() print("10 seconds later") } print("Done 1st") } dispatch_async(serialQueue) { print("Start") dispatch_async(backgroundQueue) { functionThatTakes10Seconds() print("10 seconds later") } print("Done 2nd") }
输出将是这样的:
Start
Done 1st
Start
Done 2nd
10 seconds later
10 seconds later
请注意,在调度第二个串行任务之前,前10秒任务尚未完成.现在,比较:
dispatch_async(serialQueue) { print("Start") dispatch_sync(backgroundQueue) { functionThatTakes10Seconds() print("10 seconds later") } print("Done 1st") } dispatch_async(serialQueue) { print("Start") dispatch_sync(backgroundQueue) { functionThatTakes10Seconds() print("10 seconds later") } print("Done 2nd") }
输出将是这样的:
Start
10 seconds later
Done 1st
Start
10 seconds later
Done 2nd
请注意,这次是因为同步调度了10秒的任务,所以串行队列被阻止,第二个任务在第一个任务完成之前没有启动.
在您的情况下,您正在包装的操作很可能会自己调度异步任务(因为这是网络操作的本质),因此串行调度队列本身是不够的.
您可以使用DispatchGroup来阻止串行调度队列.
dispatch_async(serialQueue) { let dg = dispatch_group_create() dispatch_group_enter(dg) print("Start") dispatch_async(backgroundQueue) { functionThatTakes10Seconds() print("10 seconds later") dispatch_group_leave(dg) } dispatch_group_wait(dg) print("Done") }
这将输出
Start
10 seconds later
Done
dg.wait()阻塞串行队列,直到dg.leave调用的数量与dg.enter调用的数量相匹配.如果使用此技术,则需要注意确保包装操作的所有可能完成路径都调用dg.leave. dg.wait()上还有一些变量,它们采用超时参数.