輕松學iOS多線程之 GCD 的常用函數

關于 iOS 多線程中 GCD 的基礎知識已在上一篇文章中詳細說明,請參看《輕松學iOS多線程之 GCD 的基本使用》進行了解,本文主要對 GCD 中的幾種常用函數做進一步概述。

在 GCD 中的常用函數主要有柵欄函數、一次性函數、延遲執行函數、快速迭代函數,最后包括 隊列組的使用以及線程間的通信

一、柵欄函數

柵欄函數的作用是用來控制任務的執行順序,必須上面的任務 1 執行完畢才執行當前柵欄任務,必須當前柵欄任務執行完畢才執行下面的任務 2。

//1.獲取并發隊列 
dispatch_queue_t queue = dispatch_queue_create("barrier", DISPATCH_QUEUE_CONCURRENT);
    //2.異步函數
dispatch_async(queue, ^{
    NSLog(@"1 --- %@", [NSThread currentThread]);
});
    //3.設置柵欄
dispatch_barrier_async(queue, ^{
    NSLog(@" ++++++++++++++ ");
});
dispatch_async(queue, ^{
    NSLog(@"2 --- %@", [NSThread currentThread]);
});

注意:柵欄函數不能使用全局并發隊列,會喪失攔截功能

二、一次性函數

一次性函數顧名思義就是在程序的運行過程中,一次性函數中的代碼只會執行一次,一次性函數的內部原理就是開始時 onceToken == 0,如果為 0 則執行,執行之后值為 -1,就不執行了。一次性函數在單例中會經常使用。

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    NSLog(@"只執行一次,默認是線程安全的");
});

注意:一次性函數不能放入懶加載中

三、延遲執行函數

在以往的學習中,我們已經知道了兩種實現延時執行的方法:

// 2秒后再調用self的run方法
[self performSelector:@selector(run) withObject:nil afterDelay:2.0];
// 2秒后再調用self的run方法
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:NO];

在 GCD 中利用 dispatch_after 也可以實現延遲執行的效果:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    NSLog(@"延時 2.0 秒執行");
});

在延遲執行中,dispatch_after 函數本身是一個異步函數,其中的隊列也可以使用自定義的隊列,它的實質是延遲 2 秒再將任務提交到隊列中,從而達到延遲執行的效果。

四、快速迭代函數(遍歷)

在以往我們知道可以使用 for 循環和 block 進行遍歷,在 GCD 中我們也可以使用 dispatch_apply 函數進行快速迭代。

dispatch_queue_t queue = dispatch_get_global_queue(0, 0);  
dispatch_apply(10, queue, ^(size_t i) {
    NSLog(@"%zd --- %@", i, [NSThread currentThread]);
});

在 dispatch_apply 函數中的三個參數分別代表著需要遍歷的次數,存放任務的隊列以及索引(就相當于 for 循環中的 i )。

注意:1. 快速迭代中的隊列只能使用并發隊列,不要使用串行隊列或主隊列,使用串行隊列時就相當于 for 循環,使用主隊列會造成死鎖

2. 在快速迭代中,會開啟子線程與主線程一起并發執行任務,執行順序是不固定的

五、隊列組的基本使用

需求:同時下載圖片一和圖片二,當兩張圖片均下載完畢后合成使之成為一張圖片。

在以前我們可以利用 GCD 中的柵欄函數解決這個問題,具體的思路為:使用異步函數 + 并發隊列開啟子線程來同時下載圖片,然后添加一個柵欄函數進行攔截,最后在柵欄函數之后進行合成圖片的任務,這里需要注意的是在合成圖片的子線程中需要回到主線程(異步函數 + 主隊列)進行展示圖片。

其實除此之外,我們也可以利用隊列組來解決這個問題,當隊列組中所有的任務都執行完畢,就會執行 dispatch_group_notify 函數。

//創建隊列組
dispatch_group_t group = dispatch_group_create();
//創建并發隊列
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
//將任務添加到隊列組中
dispatch_group_async(group, queue, ^{
    NSLog(@"1 --- %@", [NSThread currentThread]);
});
//該函數本身是異步函數
dispatch_group_notify(group, queue, ^{
    NSLog(@"--- end --- %@", [NSThread currentThread]);
});

六、線程間的通信

在子線程中下載圖片回到主線程設置并顯示:

//1.獲取隊列(串行|并行) 0 就是異步函數
dispatch_queue_t queue = dispatch_queue_create(0, 0);
//2.異步函數封裝任務提交到隊列
dispatch_async(queue, ^{       
    //3.獲取 URL
    NSURL *url = [NSURL URLWithString:@"http://c.hiphotos.baidu.com/image/pic/item/3b292df5e0fe99254674c15036a85edf8db171b2.jpg"];
    //4.下載二進制數據
    NSData *imageData = [NSData dataWithContentsOfURL:url];
    //5.將二進制數據轉換為圖片
    UIImage *image = [UIImage imageWithData:imageData];
    //6.回到主線程設置圖片(異步函數 + 主隊列)
    dispatch_async(dispatch_get_main_queue(), ^{
        self.imageView.image = image;
        NSLog(@"%@", [NSThread currentThread]);
    });
});
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容