iOS多線程開發之深入GCD
一、前言
在以前的一些系列部落格中,對iOS中線程的管理做了總結,其中涵蓋了GCD的相關基礎知識:
http://my.oschina.net/u/2340880/blog/417746。那裡面将GCD的線程管理能力,列隊組能力,通過信号和消息控制程式流程的能力都有介紹,這裡,我們繼續深入GCD的功能,通過GCD來處理一些邏輯更加複雜的代碼功能。
二、延時追加任務
當我們在程式中處理延時任務的時候,我們一般會通過兩種方式,一種是通過定時器進行延時執行,另外一種是通過如下的函數:
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay;
然而,如果我們需要在多線程中進行延時操作,上面兩種方式會顯得十分麻煩,并且徒增代碼的複雜度。GCD為我們提供了一種方式:
void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);
這個方法有三個參數,第一個參數延時的時間,第二個參數為将任務加入的隊列,第三個block為要執行的任務。示例如下:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"1233");
});
這裡通過dispatch_time來建立時間對象,将列印資訊的方法在3S後加入主線程隊列。需要注意的是,這裡隻是将任務延時加入隊列,并不是執行,如果是加入同步隊列中,則會進入等待狀态。
三、資料存取的線程安全問題
在進行多線程程式設計時,或許總會遇到一類問題,資料的競争與線程的安全。這些問題如果我們通過程式手動來控制難度将會非常大。GCD同樣為我們簡單的解決了這樣的問題。
首先,如果隻是在讀取資料,而不對資料做任何修改時,我們并不需要處理安全問題,可以讓多個任務同時進行讀取,可是如果要對資料進行寫的操作,那麼在同一時間,我們就必須隻能有一個任務在寫,GCD中有一個方法幫我們完美的解決了這個問題,代碼如下:
//建立一個隊列
dispatch_queue_t queue = dispatch_queue_create("oneQueue", DISPATCH_QUEUE_CONCURRENT);
//幾個任務同時讀操作
dispatch_async(queue, ^{
for (int i=0; i<5; i++) {
NSLog(@"read1:%d",i);
}
NSLog(@"read2:%d",i);
//此處進行寫操作
/*
下面這個函數在加入隊列時不會執行,會等待已經開始的異步執行全部完成後再執行,并且在執行時,會阻塞其他任務
執行完成後,其他任務重新進入異步執行
*/
dispatch_barrier_async(queue, ^{
NSLog(@"write:%d",i);
//繼續進行異步讀操作
NSLog(@"read3:%d",i);
NSLog(@"read4:%d",i);
NSLog(@"read5:%d",i);
列印資訊如下:
可以看出,讀操作是異步進行的,寫操作是等待後阻塞任務隊列獨立進行,結束後隊列恢複異步執行讀操作,這正是我們需要的效果。
四、GCD模式的單例
通常情況下,我們的單例會是如下的樣子:
+(instancetype)shared{
static Auto * obj;
if (obj==nil) {
obj = [[Auto alloc]init];
}
return obj;
}
這種通過讀取靜态變量的方式在大多數情況下是沒問題的,可是并不能保證程式百分百的安全,因為在多線程的操作中,會有可能初始化多個對象,在GCD中,我們可以使用如下方式:
//dispatch_once_t對象可以隻保證執行一次
static dispatch_once_t once;
dispatch_once(&once, ^{
return obj;