至于后者,我之前一直使用
dispatch_get_current_queue()
,但似乎在iOS 6或更高版本中已被弃用了。那我应该使用什么替代方案呢?dispatch_get_current_queue()
,但似乎在iOS 6或更高版本中已被弃用了。那我应该使用什么替代方案呢?“在调用方使用的任何队列上运行”模式看起来很吸引人,但最终并不是一个好主意。该队列可能是低优先级队列、主队列或具有奇怪属性的其他队列。
我喜欢的方法是说“完成块在一个具有这些属性的实现定义队列上运行:x、y、z”,让块分派到特定的队列,如果调用方想要更多的控制权。典型的指定属性集将是类似于“串行、非可重入,并与任何其他应用程序可见队列异步”的东西。
**编辑**
Catfish_Man在下面的评论中放了一个例子,我只是把它添加到他的答案中。
- (void) aMethodWithCompletionBlock:(dispatch_block_t)completionHandler
{
dispatch_async(self.workQueue, ^{
[self doSomeWork];
dispatch_async(self.callbackQueue, completionHandler);
}
}
对于您所描述的API来说,这种方法是基本上错误的。如果一个API接受一个块和一个完成块来运行,那么以下几点需要满足:
"要运行的块"应该在内部队列上运行,例如一个私有于API的队列,因此完全在API的控制之下。唯一例外的情况是如果API明确声明该块将在主队列或其中一个全局并发队列上运行。
除非与第1点相同的假设成立(例如完成块将在已知的全局队列上运行),否则完成块应始终表示为元组(queue, block)。此外,完成块应异步地在传入的队列上分派。
这些不仅仅是风格上的问题,如果您的API想要避免死锁或其他边缘情况的问题,这些措施是完全必要的,否则某一天您肯定会被吊在最近的树上。 :-)
其他答案都很好,但对我来说,答案在于结构。我有一个像这样的方法,它位于单例中:
- (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
这样我就可以将调度函数的中心化操作放在另一个线程上。
在使用dispatch_get_current_queue
时,您需要谨慎。从头文件中可以看到:
仅建议用于调试和记录日志:
代码不能对返回的队列做任何假设,除非它是全局队列或者是代码本身创建的队列。如果该队列不是通过 dispatch_get_current_queue()函数返回的队列,则不能假定同步执行进入队列是安全的。
您可以采取以下两种方式之一:
保留对您最初发布的队列的引用(如果您是通过dispatch_queue_create
创建的),并从那时起一直使用它。
通过dispatch_get_global_queue
使用系统定义的队列,并跟踪您正在使用哪个队列。
实际上,以前依赖系统来跟踪您所在的队列,现在您将不得不自己进行跟踪。
dispatch_get_current_queue()
找出原始发布队列,那么如何“保留对其的引用”?有时需要知道运行在哪个队列上的代码并不能控制或知道它所在的队列。我的很多代码可以(而且应该)在后台队列上执行,但偶尔需要更新 GUI(进度条等),因此需要将其转换到主队列上进行 dispatch_sync()
操作。如果已经在主队列上,dispatch_sync()
将会永久锁定。重构我的代码需要数月时间。 - Abhi Beckert苹果已经废弃了 dispatch_get_current_queue()
,但在另一个地方留下了漏洞,因此我们仍然能够获得当前的调度队列:
if let currentDispatch = OperationQueue.current?.underlyingQueue {
print(currentDispatch)
// Do stuff
}
至少对于主队列来说,这个方法是有效的。需要注意的是,自iOS 8以来,underlyingQueue
属性已经可用。
如果您需要在原始队列中执行完成块,则可以直接使用OperationQueue
,而无需使用GCD。
对于仍需要进行队列比较的人,您可以通过标签或指定方式来比较队列。 请查看此链接:https://dev59.com/y2jWa4cB1Zd3GeqPu-Xv#23220741
这是一个我也来凑热闹的回答。所以我将谈谈我们的用例。
我们有一个服务层和 UI 层(以及其他层)。服务层在后台运行任务。(数据操作任务,CoreData 任务,网络调用等)服务层有几个操作队列来满足 UI 层的需求。
UI 层依赖于服务层进行工作,然后运行成功完成块。此块可以具有 UIKit 代码。一个简单的用例是从服务器获取所有消息并重新加载集合视图。
在这里,我们保证传递到服务层的块会在调用服务的队列上分派。由于 dispatch_get_current_queue 是一种已弃用的方法,我们使用 NSOperationQueue.currentQueue 来获取调用者的当前队列。关于此属性的重要注释:
从运行中的操作外部调用此方法通常会返回 nil。
由于我们总是在已知队列(我们自定义队列和主队列)上调用我们的服务,因此对我们很有效。我们确实有一些情况,其中 serviceA 可以调用 serviceB,serviceB 可以调用 serviceC。由于我们控制第一个服务调用的位置,我们知道其余服务将遵循相同的规则。
因此,NSOperationQueue.currentQueue将始终返回我们的队列之一或MainQueue。
dispatch_get_current_queue()
在iOS 6中已经被弃用了?文档上并没有提到。 - jeredispatch_async(dispatch_get_global_queue(0, 0), ^{ NSLog(@"q(0,0) 是 %@", dispatch_get_current_queue()); NSLog(@"cq(0,0) 是 %@", [NSOperationQueue currentQueue]); });
q(0,0) 是 <OS_dispatch_queue_root: com.apple.root.default-qos[0x100195140]> cq(0,0) 是 (null)----- 已弃用或不推荐使用,dispatch_get_current_queue() 看起来是我在所有情况下报告当前队列的唯一解决方案 - godzilla