如何判斷當前線程是主線程

在開發應用程序時,我們異步請求數據處理後,需要回到主線程刷新UI,一般情況下直接通過以下方式異步回到主線程: 

  dispatch_async(dispatch_get_main_queue(), ^{
        //  主線程刷新UI操作

    }); 


看過SDWebImage源碼的應該看過它裏面有這樣一個宏:

#ifndef dispatch_main_async_safe
#define dispatch_main_async_safe(block)\
    if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(dispatch_get_main_queue())) == 0) {\
        block();\
    } else {\
        dispatch_async(dispatch_get_main_queue(), block);\
    }
#endif 


其中通過如下一句代碼來判斷當前是否是在主線程

strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(dispatch_get_main_queue())) == 0


 
上述判斷用到了strcmp函數和dispatch_queue_get_label函數

strcmp(字符串1,字符串2):C語言中的函數,用於比較2個字符串的大小

比較規則:對兩個字符串自左至右逐個字符相比(按ASCII碼值大小比較),直到出現不同的字符或遇到‘\0’爲止。如果全部字符相同,則認爲相等;若出現不相同的字符,則以第一個不相同的字符的比較結果爲準

返回值: 
(1)字符串1=字符串2,返回0 
(2)字符串1>字符串2,返回一個正整數 
(3)字符串1<字符串2,返回一個負整數。

dispatch_queue_get_label:獲取指定隊列的label名稱,返回值是C語言的字符串

如果沒有指定隊列的名稱,就返回NULL,如果傳入的是DISPATCH_CURRENT_QUEUE_LABEL則返回當前隊列的label名稱

上述方法的思路是通過判斷當前隊列是否是主隊列來判斷是否在主線程。

既然如此,我們是否可以直接通過GCD提供的方法dispatch_get_current_queue()獲取當前隊列來判斷是不是主隊列?

dispatch_get_current_queue()在iOS 6.0時已經廢棄了,棄用的原因在於當獲取的目標隊列正好是當前隊列時會同步阻塞導致死鎖。點擊查看詳細講解

還有一個比較常見的,判斷是否是主線程的方法

   

BOOL isMain = [NSThread isMainThread];


 
這個方法在大部分情況下是有效的,但是有些情況下會出現問題失效情景, 
原因在於下面這句話:

MapKit: It's not safe to call MKMapView's addOverlay on a non-main-queue, even if it is executed on the main thread #7053
 
即在非主隊列即使是在主線程調用MKMapView’s addOverlay的方法也是不安全的。因爲上述方法只會檢查當前是否在主線程,而不去判斷是否在主隊列

綜上所述:

1、每個應用程序只有一個主線程,主線程上可能有很多不同的隊列在運行 
2、主隊列一定在主線程運行,非主隊列不一定不在主線程 
3、有些庫的運行不但依賴主線程,更是依賴主隊列,例如:MapKit 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章