我有一个接受块和完成块的方法。第一个块应该在后台运行,而完成块应该在调用方法的任何队列中运行。
对于后者,我总是使用dispatch_get_current_queue()
,但似乎在iOS 6或更高版本中已弃用。我该怎么用?
答案 0 :(得分:62)
“在呼叫者所在的任何队列上运行”的模式很有吸引力,但最终不是一个好主意。该队列可以是低优先级队列,主队列,或其他具有奇数属性的队列。
我最喜欢的方法是说“完成块在具有以下属性的实现定义队列上运行:x,y,z”,并且如果调用者想要更多控制,则让块调度到特定队列。要指定的一组典型属性类似于“串行,非重入和相对于任何其他应用程序可见队列的异步”。
**编辑**
Catfish_Man在下面的评论中举了一个例子,我只是将它添加到他的答案中。
- (void) aMethodWithCompletionBlock:(dispatch_block_t)completionHandler
{
dispatch_async(self.workQueue, ^{
[self doSomeWork];
dispatch_async(self.callbackQueue, completionHandler);
}
}
答案 1 :(得分:24)
这基本上是您要描述的API的错误方法。如果API接受要运行的块和完成块,则必须满足以下要求:
“要运行的块”应该在内部队列上运行,例如一个私有的API队列,因此完全在该API的控制之下。唯一的例外是API是否明确声明该块将在主队列或其中一个全局并发队列上运行。
完成块应始终表示为元组(队列,块),除非与#1相同的假设成立,例如完成块将在已知的全局队列上运行。此外,还应在传入队列中调度完成块async。
这些不仅仅是风格点,如果您的API要安全地摆脱死锁或其他边缘情况行为,那么它们将是完全必要的,否则有一天会让您从最近的树上挂起来。 : - )
答案 2 :(得分:14)
其他答案很棒,但对我而言,答案是结构性的。我有一个像Singleton这样的方法:
- (void) dispatchOnHighPriorityNonMainQueue:(simplest_block)block forceAsync:(BOOL)forceAsync {
if (forceAsync || [NSThread isMainThread])
dispatch_async_on_high_priority_queue(block);
else
block();
}
有两个依赖关系,它们是:
static void dispatch_async_on_high_priority_queue(dispatch_block_t block) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), block);
}
和
typedef void (^simplest_block)(void); // also could use dispatch_block_t
这样我就可以集中调用另一个线程上的调度。
答案 3 :(得分:12)
首先,您应该谨慎使用dispatch_get_current_queue
。从头文件:
建议仅用于调试和记录目的:
代码 除非它,否则不得对返回的队列做任何假设 是代码本身创建的全局队列之一或队列。 代码不能假设同步执行到队列中 如果该队列不是返回的队列,则从死锁中安全 dispatch_get_current_queue()。
您可以执行以下任一操作之一:
保留对您最初发布的队列的引用(如果您是通过dispatch_queue_create
创建的),并在此之后使用该队列。
通过dispatch_get_global_queue
使用系统定义的队列,并跟踪您正在使用的队列。
在以前依靠系统跟踪您所在的队列的同时,您将不得不自己完成。
答案 4 :(得分:4)
对于仍然需要进行队列比较的人,可以按标签比较队列或指定队列。 请检查此https://stackoverflow.com/a/23220741/1531141
答案 5 :(得分:4)
Apple已弃用dispatch_get_current_queue()
,但在其他地方留下了漏洞,因此我们仍然可以获得当前的调度队列:
if let currentDispatch = OperationQueue.current?.underlyingQueue {
print(currentDispatch)
// Do stuff
}
这至少适用于主队列。
请注意,从iOS 8开始,underlyingQueue
属性可用。
如果您需要在原始队列中执行完成块,您也可以直接使用OperationQueue
,我的意思是没有GCD。
答案 6 :(得分:0)
这也是我的回答。所以我将谈谈我们的用例。
我们有一个服务层和UI层(以及其他层)。服务层在后台运行任务。 (数据操作任务,CoreData任务,网络调用等)。服务层有一些操作队列,以满足UI层的需要。
UI层依赖于服务层来完成其工作,然后运行成功完成块。该块可以包含UIKit代码。一个简单的用例是从服务器获取所有消息并重新加载集合视图。
这里我们保证传入服务层的块在调用服务的队列上调度。由于dispatch_get_current_queue是不推荐使用的方法,因此我们使用NSOperationQueue.currentQueue来获取调用者的当前队列。关于这家酒店的重要说明。
从正在运行的操作的上下文之外调用此方法 通常导致返回nil。
由于我们总是在已知队列(我们的自定义队列和主队列)上调用我们的服务,因此这对我们很有用。我们确实有这样的情况:serviceA可以调用serviceB来调用serviceC。由于我们控制第一次服务呼叫的来源,我们知道其他服务将遵循相同的规则。
所以NSOperationQueue.currentQueue将始终返回我们的一个队列或MainQueue。