標籤:
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); } }); dispatch_async(queue, ^{ for (int i=0; i<5; i++) { NSLog(@"read2:%d",i); } }); //此處進行寫操作 /* 下面這個函數在排入佇列時不會執行,會等待已經開始的非同步執行全部完成後再執行,並且在執行時,會阻塞其他任務 執行完成後,其他任務重新進入非同步執行 */ dispatch_barrier_async(queue, ^{ for (int i=0; i<5; i++) { NSLog(@"write:%d",i); } }); //繼續進行非同步讀操作 dispatch_async(queue, ^{ for (int i=0; i<5; i++) { NSLog(@"read3:%d",i); } }); dispatch_async(queue, ^{ for (int i=0; i<5; i++) { NSLog(@"read4:%d",i); } }); dispatch_async(queue, ^{ for (int i=0; i<5; i++) { NSLog(@"read5:%d",i); } });
列印資訊如下:
可以看出,讀操作是非同步進行的,寫操作是等待後阻塞任務隊列獨立進行,結束後隊列恢複非同步執行讀操作,這正是我們需要的效果。
四、GCD模式的單例
通常情況下,我們的單例會是如下的樣子:
+(instancetype)shared{ static Auto * obj; if (obj==nil) { obj = [[Auto alloc]init]; } return obj;}
這種通過讀取靜態變數的方式在大多數情況下是沒問題的,可是並不能保證程式百分百的安全,因為在多線程的操作中,會有可能初始化多個對象,在GCD中,我們可以使用如下方式:
+(instancetype)shared{ static Auto * obj; //dispatch_once_t對象可以只保證執行一次 static dispatch_once_t once; dispatch_once(&once, ^{ obj = [[Auto alloc]init]; }); return obj; }
iOS多線程開發之深入GCD