iOS多線程--GCD

只需知道如何開線程、會看相關的第三方框架即可。

簡介

-

兩個核心概念

任務:執(zhí)行什么操作
隊列:用來存放任務

隊列類型:

  • 并發(fā)隊列(Concurrent Dispatch Queue)
    可以讓多個任務并發(fā)執(zhí)行(自動開啟多個線程同時執(zhí)行任務)
    在異步dispatch_async函數(shù)下才有效

  • 串行隊列(Serial Dispatch Queue)
    讓任務一個接著一個地執(zhí)行(一個任務執(zhí)行完畢后,再執(zhí)行下一個)
    按照FIFO順序執(zhí)行。

任務派發(fā):

  • 同步
    指阻塞當前線程,既要等待添加的耗時任務塊Block完成后,函數(shù)才能返回,后面的代碼才能繼續(xù)執(zhí)行。
  • 異步
    指將任務添加到隊列后,函數(shù)立即返回,后面的代碼不用等待添加的任務完成即可馬上執(zhí)行。異步提交無法確定任務執(zhí)行順序。

GCD多線程經(jīng)常會使用 同步函數(shù)dispatch_sync、異步函數(shù)dispatch_async,向指定隊列 添加任務。

分辨

-

各種隊列的執(zhí)行效果

-

主隊列(一種串行隊列)

凡是放到主隊列中的任務,都必須在主線程中執(zhí)行。

1.異步函數(shù)+主隊列

串行執(zhí)行,所有任務都在主線程中執(zhí)行,不會開線程

2.同步函數(shù)+主隊列————》會死鎖!一般不用。

主隊列的特點:如果主隊列發(fā)現(xiàn)當前主線程有任務在執(zhí)行,那么它會暫停隊列中的任務,直到主線程空閑為止。

GCD實現(xiàn)線程間通信

說明:在更新UI時回到了主線程(通過新設一個同步/異步函數(shù),隊列參數(shù)為主隊列)

  • 開子線程做異步任務
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        //...做一些任務
        
        dispatch_sync(dispatch_get_main_queue(), ^{
            //回到主線程,更新UI
        });
    });

舉例,開啟子線程下載圖片

   //1.獲取一個 全局串行隊列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  
   __weak typeof(self) weakSelf = self;
   //2.把任務添加到隊列中執(zhí)行
    dispatch_async(queue, ^{
        NSURL *url = [NSURL URLWithString:_imgString];
        NSData *imageData = [NSData dataWithContentsOfURL:url];
        UIImage * bgImage = [UIImage imageWithData:imageData];
        bgImage = [bgImage applyLightEffectAtFrame:CGRectMake(0, 0, bgImage.size.width, bgImage.size.height)];
        //3.回到主線程
        dispatch_async(dispatch_get_main_queue(), ^{
            weakSelf.backImageView.image = bgImage;
        });
    });

GCD常用函數(shù)

  • 延遲執(zhí)行
int64_t delayInSeconds = 10.0;      // 延遲的時間

dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){           
     // do something  ...  ... 
});

或

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)( 10.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    // ...     
});

  • 一次性代碼
    這個應用程序只執(zhí)行一次,不再執(zhí)行
    static dispatch_once_t onceToken;
    
    dispatch_once(&onceToken, ^{
        //...
    });

不能應用于懶加載。應用于單例模式。

  • 柵欄函數(shù)
    用于控制異步函數(shù)的執(zhí)行順序,只有執(zhí)行完柵欄函數(shù),才能執(zhí)行后面的隊列任務。使用時,必須自己創(chuàng)建隊列,不能使用全局并發(fā)隊列。

同步函數(shù)沒有必要用柵欄函數(shù)。

  • 快速迭代(遍歷)
    內(nèi)部會開子線程和主線程一起完成遍歷任務,異步執(zhí)行任務
  • 主線程異步任務
    dispatch_async(dispatch_get_main_queue(), ^{
    
    });
  • 柵欄函數(shù)
    用于控制異步函數(shù)的執(zhí)行順序??杀苊鈹?shù)據(jù)競爭。使用時,必須自己創(chuàng)建隊列,不能使用全局并發(fā)隊列。
    //創(chuàng)建隊列
    dispatch_queue_t queue = dispatch_queue_create("download", DISPATCH_QUEUE_CONCURRENT);
    
    //異步函數(shù)
    dispatch_async(queue, ^{
        
        //....異步任務1
    });
    
    dispatch_async(queue, ^{
        
        //....異步任務2
    });
    
    //柵欄函數(shù)
    dispatch_barrier_async(queue, ^{
        
        //...
    });

一個dispatch barrier允許在一個并發(fā)隊列中創(chuàng)建一個同步點。當在并發(fā)隊列中遇到一個barrier, 他會延遲執(zhí)行barrier的block,等待所有在barrier之前提交的blocks執(zhí)行結束。 這時,barrier block自己開始執(zhí)行。 之后, 隊列繼續(xù)正常的執(zhí)行操作。

  • 隊列組
    某幾個隊列的任務都完成后,再執(zhí)行其他任務
    //創(chuàng)建隊列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    /創(chuàng)建隊列組
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_async(group, queue, ^{
        //...異步任務1
    });
    dispatch_group_async(group, queue, ^{
        //...異步任務2
    });
    dispatch_group_async(group, queue, ^{
        //...異步任務3
    });
    
    //  攔截通知,當隊列組里的任務都完成了,會進入下面這個方法
    dispatch_group_notify(group, queue, ^{
        //... ... 
    });

如,加載多個圖片

// 使用Dispatch Group追加block到Global Group Queue,這些block如果全部執(zhí)行完畢,
就會執(zhí)行Main Dispatch Queue中的結束處理的block。
// 創(chuàng)建隊列組
dispatch_group_t group = dispatch_group_create();
// 獲取全局并發(fā)隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_async(group, queue, ^{ /*加載圖片1 */ });
dispatch_group_async(group, queue, ^{ /*加載圖片2 */ });
dispatch_group_async(group, queue, ^{ /*加載圖片3 */ }); 
// 當并發(fā)隊列組中的任務執(zhí)行完畢后才會執(zhí)行這里的代碼
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        // 合并圖片
});
  • 定時任務
    /* 在指定線程上定義計時器 */
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    
    /* 開始的時間 */
    dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC));
    /* 設置計時器 ,時間間隔 5s  */
    dispatch_source_set_timer(_timer, when, 5.0 * NSEC_PER_SEC, 0);
    /* 計時器回調(diào)block */
    dispatch_source_set_event_handler(_timer, ^{
        // do  something
        NSLog(@"需要做的任務!");
        
    });
    /* 開啟計時器 */
    dispatch_resume(_timer);

    self.timer = _timer;   // 強引用計時器對象(必須)

必須銷毀self.timer才能終止定時任務:self.timer = nil ;

GCD取消線程

可以取消還未執(zhí)行的線程。但是沒辦法做到取消一個正在執(zhí)行的線程。

  • 取消函數(shù) dispatch_block_cancel
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_block_t block1 = dispatch_block_create(0, ^{
    NSLog(@"block1");
});
dispatch_block_t block2 = dispatch_block_create(0, ^{
    NSLog(@"block2");
});
dispatch_block_t block3 = dispatch_block_create(0, ^{
    NSLog(@"block3");
});
    
dispatch_async(queue, block1);
dispatch_async(queue, block2);
dispatch_async(queue, block3);

dispatch_block_cancel(block3);   // 取消 block3

投機取巧:使用臨時變量 + return 方式取消 正在執(zhí)行的Block。

__block BOOL gcdFlag = NO; // 臨時變量
dispatch_async(dispatch_get_global_queue(0, 0), ^{
    for (long i=0; i<1000; i++) {
        NSLog(@"正在執(zhí)行第i次:%ld",i);
        sleep(0.1);
        if (gcdFlag==YES) { // 判斷并終止
            NSLog(@"終止");
            return ;
        }
    };
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    NSLog(@"我要停止啦");
    gcdFlag = YES;
});
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容