iOS知识小集之main-queue!=main-thread
GCD main queue和main thread的关系
dispatch_get_main_queue()返回main queue,该队列会被绑定到main thread,所以我们如果我们将block提交到main queue,那么该block将会在主线程中执行。
dispatch_sync(queue, block)向 main queue提交block
1 | /// Current thread is main thread |
大家有没有注意到,Log输出表明执行Block时的线程为主线程,根据我们以往的经验,dispatch_get_global_queue获取到的队列,队列中的Block应该是在Secondly thread中执行,为什么这里会是在主线程中呢。
答案就是在dispatch_sync语句,libdispatch在commit中进行了优化,只要目标queue不是main queue,那么提交的Block就会直接在原线程中执行,这就能解释为什么上面的demo程序中输出的Log显示是主线程。
那么,这种会不会有潜在的问题呢?
isMainThread带来的潜在问题
首先,我们看一个Radar,大概意思是,即使MapKit框架的addOverlay方法在主线程执行,但是由于其不是在main queue中执行的,会导致Crash,这是因为MapKit内部在main queue中使用dispatch_queue_set_specific设置了数据,当你在其它队列中执行时,会由于没有该数据从而导致Crash。
避免使用isMainThread
所以,我们需要避免使用isMainThread,而是判断是不是main queue,我们可以使用两种方法来判断:
- 使用
dispatch_queue_set_specific在main queue上设置flag,然后做判断,有该flag即为main queue. - 判断
dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL) == dispatch_queue_get_label(dispatch_get_main_queue()),main queue设置了label,可以通过其来判断。
总结
main queue中的Block一定在主线程中执行。- 主线程可以对应多个
queue,既可以有任意的队列,其Block可以在主线程中执行。