天天看點

iOS多線程開發之深入GCDiOS多線程開發之深入GCD

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);

列印資訊如下:

iOS多線程開發之深入GCDiOS多線程開發之深入GCD

可以看出,讀操作是異步進行的,寫操作是等待後阻塞任務隊列獨立進行,結束後隊列恢複異步執行讀操作,這正是我們需要的效果。

四、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;

繼續閱讀