你好,歡迎來到IOS教程網

 Ios教程網 >> IOS訊息 >> 關於IOS >> GCD使用詳解

GCD使用詳解

編輯:關於IOS
1.什麼是GCD 全稱是Grand Central Dispatch,可譯為“牛X的中樞調度器” 純C語言,提供了非常多強大的函數 2.GCD的優勢 GCD是蘋果公司為多核的並行運算提出的解決方案 GCD會自動利用更多的CPU內核(比如雙核、四核) GCD會自動管理線程的生命周期(創建線程、調度任務、銷毀線程) 程序員只需要告訴GCD想要執行什麼任務,不需要編寫任何線程管理代碼 3.GCD中有2個核心概念 任務:執行什麼操作 隊列:用來存放任務 將任務添加到隊列中 GCD會自動將隊列中的任務取出,放到對應的線程中執行 任務的取出遵循隊列的FIFO原則:先進先出,後進後出 有4個術語比較容易混淆:同步、異步、並發、串行 同步和異步決定了要不要開啟新的線程 同步:在當前線程中執行任務,不具備開啟新線程的能力 異步:在新的線程中執行任務,具備開啟新線程的能力 並發和串行決定了任務的執行方式 並發:多個任務並發(同時)執行 串行:一個任務執行完畢後,再執行下一個任務
代碼分析上面的四個概念:

#pragma mark - 1異步並發
- (void)asyncGlobal {
    // 取得全局並發隊列
     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // 使用異步調用
    dispatch_async(queue, ^{
        NSLog(@"result1, %@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"result2, %@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"result3, %@",[NSThread currentThread]);
    });
}
#pragma mark - 2異步串行
- (void)asyncSerial {
    // 創建串行隊列
    dispatch_queue_t queue = dispatch_queue_create("Serial", NULL);
    // 使用異步調用
    dispatch_async(queue, ^{
        NSLog(@"result1, %@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"result2, %@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"result3, %@",[NSThread currentThread]);
    });
}
#pragma mark - 3同步並發
- (void)syncGlobal {
    // 取得全局並發隊列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // 使用同步調用
    dispatch_sync(queue, ^{
        NSLog(@"result1, %@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"result2, %@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"result3, %@",[NSThread currentThread]);
    });
}
#pragma mark - 4同步串行
- (void)syncSerial {
    // 創建串行隊列
    dispatch_queue_t queue = dispatch_queue_create("Serial", NULL);
    // 使用同步調用
    dispatch_sync(queue, ^{
        NSLog(@"result1, %@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"result2, %@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"result3, %@",[NSThread currentThread]);
    });
}

上面的代碼,我們可以通過觀察打印線程信息 [NSThread currentThread] 來判斷是否有開啟新的線程及開啟新的線程的情況。上面的執行結果,可以用下面的圖表來描述:

用文字總結,結果如下:

同步 (sync)  不開起新的線程

並發隊列:     不開起新的線程(用默認的主線程)

串行隊列:     不開起新的線程(用默認的主線程)

 

異步 (async) 開啟新的線程

並發隊列:     能開啟多條線程(取出隊列中的任務,子線程執行;接著取出隊列中後面的任務,開辟其他線程執行這條任務....)

串行隊列:     只開啟一條子線程(取出隊列中的任務,子線程執行,執行完畢後,繼續取出任務,子線程繼續執行....)

4.線程間通信示例 從子線程回到主線程

dispatch_async(

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

//執行耗時的異步操作...

dispatch_async(dispatch_get_main_queue(),^{

// 回到主線程,執行UI刷新操作

});

});

上面的代碼片段是經典的線程間通信使用方法。

Example:

從網絡下載圖片資源,並顯示到主線程UI上面

  1. // 並發隊列
  2.     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  3.     // 開啟子線程
  4.     dispatch_async(queue, ^{
  5.         NSURL *url = [NSURL URLWithString:@"http://pic.cnr.cn/list/201209/W020120914588236390160.jpg"];
  6.         NSData *data = [NSData dataWithContentsOfURL:url];
  7.         UIImage *image = [UIImage imageWithData:data];
  8.         // 講image信息在主線程上面呈現(這樣就不會卡死了)
  9.         dispatch_async(dispatch_get_main_queue(), ^{
  10.             self.myImageView.image = image;
  11.         });
  12.     });

5. 隊列組

有這麼一種需求 首先:分別異步執行兩個耗時的操作 其次:等兩個異步操作都執行完畢後,再回到主線程執行操作

  1. dispatch_group_t group =  dispatch_group_create();
  2. dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  3.     // 執行1個耗時的異步操作
  4. });
  5. dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  6.     // 執行1個耗時的異步操作
  7. });
  8. dispatch_group_notify(group, dispatch_get_main_queue(), ^{
  9.     // 等前面的異步操作都執行完畢後,回到主線程...
  10. });
Example: 從網絡異步下載兩張圖片,當兩張圖片均下載完畢後,完成圖片的拼接操作 效果圖如下: 實現代碼如下:
  1. #pragma mark - 並發下載多張圖片
  2. - (void)downloadImage {
  3.     dispatch_group_t group = dispatch_group_create();
  4.     __block UIImage *image1 = nil;
  5.     dispatch_group_async(group, GlobalQueue, ^{
  6.         image1 = [self imageWithUrl:@"http://www.2qqtouxiang.cn/uploads/allimg/100917/1_100917230241_2.jpg"];
  7.     });
  8.     __block UIImage *image2 = nil;
  9.     dispatch_group_async(group, GlobalQueue, ^{
  10.         image2 = [self imageWithUrl:@"http://img3.douban.com/view/photo/albumicon/public/p1446733286.jpg"];
  11.     });
  12.     // 上面兩個GCD是異步同時下載圖片的,下面這句代碼是等到兩張圖片全部下載完畢後便會執行
  13.     dispatch_group_notify(group, MainQueue, ^{
  14.         self.image1.image = image1;
  15.         self.image2.image = image2;
  16.         // 拼接圖片
  17.         UIGraphicsBeginImageContextWithOptions(CGSizeMake(100, 100), NO, 0.0);
  18.         [image1 drawInRect:CGRectMake(0, 0, 50, 100)];
  19.         [image2 drawInRect:CGRectMake(50, 0, 50, 100)];
  20.         self.myImage.image = UIGraphicsGetImageFromCurrentImageContext();
  21.         UIGraphicsEndImageContext();
  22.     });
  23. }
  24. - (UIImage *)imageWithUrl:(NSString *)urlStr {
  25.     NSURL *url = [NSURL URLWithString:urlStr];
  26.     NSData *data = [NSData dataWithContentsOfURL:url];
  27.     return [UIImage imageWithData:data];
  28. }

6. GCD其他好用的方法

  1. #pragma mark - 延時執行
  2. - (void)delay {
  3.     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(33 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  4.         NSLog(@"延時3秒執行~~~");
  5.     });
  6. }
  7. #pragma mark - 不管調用多少次只執行一次
  8. - (void)doOnce {
  9.     static dispatch_once_t onceToken;
  10.     dispatch_once(&onceToken, ^{
  11.         NSLog(@"一次性執行");
  12.     });
  13. }
  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved