dispatch_queue_t
隊(duì)列對(duì)應(yīng)一個(gè)dispatch_queue_t對(duì)象即:
dispatch_queue_t queue;
類似普通OC對(duì)象,可以用dispatch_retain()和dispatch_release()對(duì)其進(jìn)行內(nèi)存管理,當(dāng)一個(gè)任務(wù)加入到一個(gè)queue中的時(shí)候,任務(wù)會(huì)retain這個(gè)queue,直到任務(wù)執(zhí)行完成才會(huì)release。iOS6之后dispatch對(duì)象已經(jīng)支持ARC,所以在ARC工程之下,我們可以不用擔(dān)心他的內(nèi)存。
一般情況下只需要用strong申明一個(gè)dispatch的屬性。
@property (nonatomic, strong) dispatch_queue_t queue;
如果你是寫(xiě)一個(gè)framework,framework的使用者的SDK有可能還是古董級(jí)的iOS6之前。那么你需要根據(jù)OS_OBJECT_USE_OBJC做一個(gè)判斷是使用strong還是assign。(一般github上的優(yōu)秀第三方庫(kù)都會(huì)這么做)
#if OS_OBJECT_USE_OBJC
@property (nonatomic, strong) dispatch_queue_t queue;
#else
@property (nonatomic, assign) dispatch_queue_t queue;
#endif
<li><h4>獲取主線程隊(duì)列<h4></li>
主線程是我們最常用的線程,獲取主線程隊(duì)列的方法很簡(jiǎn)單:
dispatch_queue_t mainQueue;
mainQueue = dispatch_get_main_queue();
假設(shè)要在主線程更新UI:
dispatch_async(dispatch_get_main_queue(), ^{
[self updateUI];
});
執(zhí)行加入到主線程隊(duì)列的block,App會(huì)調(diào)用dispatch_main(), NSApplicationMain(),或者在主線程使用CFRunLoop。
<li><h4>獲取全局隊(duì)列<h4></li>
除了主線程隊(duì)列,GCD提供了幾個(gè)全局隊(duì)列,可以直接獲取使用
dispatch_queue_t dispatch_get_global_queue(long identifier, unsigned long flags);
dispatch_get_global_queue方法獲取的全局隊(duì)列都是并行隊(duì)列,并且隊(duì)列不能被修改,也就是說(shuō)對(duì)全局隊(duì)列調(diào)用dispatch_suspend(), dispatch_resume(), dispatch_set_context()等方法無(wú)效。
全局隊(duì)列對(duì)于程序來(lái)說(shuō)是全局的,retain和release會(huì)被全局隊(duì)列忽略。所以,我們不需要存儲(chǔ)這些隊(duì)列的引用數(shù)。
identifier: 用以標(biāo)識(shí)隊(duì)列優(yōu)先級(jí),推薦用qos_class枚舉作為參數(shù),也可以使用dispatch_queue_priority_t
flags: 預(yù)留字段,傳入任何非0的值都可能導(dǎo)致返回NULL
代碼示例:
dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
全局隊(duì)列的四種類型
DISPATCH_QUEUE_PRIORITY_HIGH : 最高優(yōu)先級(jí),交互級(jí)別。使用這個(gè)優(yōu)先級(jí)會(huì)占用幾乎所有的系統(tǒng)CUP和I/O帶寬,僅限用于交互的UI操作,比如處理點(diǎn)擊事件,繪制圖像到屏幕上,動(dòng)畫(huà)等
DISPATCH_QUEUE_PRIORITY_DEFAULT : 默認(rèn)優(yōu)先級(jí),當(dāng)沒(méi)有設(shè)置優(yōu)先級(jí)的時(shí)候,線程默認(rèn)優(yōu)先級(jí)。一般情況下用的都是這個(gè)優(yōu)先級(jí)
DISPATCH_QUEUE_PRIORITY_LOW : 普通優(yōu)先級(jí),主要用于不需要立即返回的任務(wù)
DISPATCH_QUEUE_PRIORITY_BACKGROUND : 后臺(tái)優(yōu)先級(jí),用于用戶幾乎不感知的任務(wù)。它會(huì)等待所有比它級(jí)別高的隊(duì)列中的任務(wù)執(zhí)行完或CPU空閑的時(shí)候才會(huì)執(zhí)行自己的任務(wù)。例如磁盤的讀寫(xiě)操作非常耗時(shí),如果我們不需要立即獲取到磁盤的數(shù)據(jù),我們可以把讀寫(xiě)任務(wù)放到后臺(tái)隊(duì)列中,這樣讀寫(xiě)任務(wù)只會(huì)在恰當(dāng)?shù)臅r(shí)候去執(zhí)行而不會(huì)影響需要更改優(yōu)先級(jí)的其他任務(wù),整個(gè)程序也會(huì)更加有效率。
由于NULL等于0,也就是DISPATCH_QUEUE_PRIORITY_DEFAULT,所以將0或者NULL傳入作為參數(shù)返回的是默認(rèn)優(yōu)先級(jí):
dispatch_get_global_queue(NULL, NULL)
<li><h4>創(chuàng)建串行隊(duì)列&并發(fā)隊(duì)列<h4></li>
當(dāng)無(wú)法獲取到理想的隊(duì)列時(shí),我們可以自己創(chuàng)建隊(duì)列:
dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
label: 隊(duì)列的名稱,調(diào)試的時(shí)候可以區(qū)分其他的隊(duì)列
attr: 隊(duì)列的屬性,dispatch_queue_attr_t類型。用以標(biāo)識(shí)隊(duì)列串行,并行,以及優(yōu)先級(jí)等信息
attr參數(shù)有三種傳值方式:
// 串行
#define DISPATCH_QUEUE_SERIAL NULL
// 并行
#define DISPATCH_QUEUE_CONCURRENT \
DISPATCH_GLOBAL_OBJECT(dispatch_queue_attr_t, \
_dispatch_queue_attr_concurrent)
// 自定義屬性值
dispatch_queue_attr_t dispatch_queue_attr_make_with_qos_class(dispatch_queue_attr_t attr, dispatch_qos_class_t qos_class, int relative_priority);
DISPATCH_QUEUE_SERIAL 或者 NULL,表示創(chuàng)建串行隊(duì)列,優(yōu)先級(jí)為目標(biāo)隊(duì)列優(yōu)先級(jí)。
DISPATCH_QUEUE_CONCURRENT,表示創(chuàng)建并行隊(duì)列,優(yōu)先級(jí)也為目標(biāo)隊(duì)列優(yōu)先級(jí)。
另外, 自定義屬性值
dispatch_queue_attr_make_with_qos_class函數(shù)可以創(chuàng)建帶有優(yōu)先級(jí)的dispatch_queue_attr_t對(duì)象。通過(guò)這個(gè)對(duì)象可以自定義queue的優(yōu)先級(jí)。
attr: 傳入DISPATCH_QUEUE_SERIAL、NULL或DISPATCH_QUEUE_CONCURRENT,表示串行或者并行
qos_class: 傳入qos_class枚舉,表示優(yōu)先級(jí)級(jí)別
relative_priority: 相對(duì)于qos_class的相對(duì)優(yōu)先級(jí),qos_class用于區(qū)分大的優(yōu)先級(jí)級(jí)別,relative_priority表示大級(jí)別下的小級(jí)別。relative_priority必須大于QOS_MIN_RELATIVE_PRIORITY小于0,否則將返回NULL。從GCD源碼中可以查到QOS_MIN_RELATIVE_PRIORITY等于-15
使用dispatch_queue_attr_make_with_qos_class創(chuàng)建隊(duì)列時(shí),需要注意,非法的參數(shù)可能導(dǎo)致dispatch_queue_attr_make_with_qos_class返回NULL,dispatch_queue_create傳入NULL會(huì)創(chuàng)建出串行隊(duì)列。寫(xiě)代碼過(guò)程中需要確保這是否是預(yù)期的結(jié)果
常用創(chuàng)建隊(duì)列代碼示例:
//串行隊(duì)列
dispatch_queue_t serialQueue;
serialQueue = dispatch_queue_create("com.example.SerialQueue", NULL);
//并發(fā)隊(duì)列
dispatch_queue_t concurrentQueue;
concurrentQueue = dispatch_queue_create("com.example.ConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);