iOS GCD的基本用法

1、GCD簡(jiǎn)介

Grand Central Dispatch (GCD),是蘋果推出的多線程解決方案,它主要用于優(yōu)化應(yīng)用程序以支持多核處理器以及其他對(duì)稱多處理系統(tǒng)。它是一個(gè)在線程池模式的基礎(chǔ)上執(zhí)行的并發(fā)任務(wù)。

2、任務(wù)和隊(duì)列

  • 任務(wù):
    就是執(zhí)行操作的意思,在GCD中使用 block 封裝。block就是一個(gè)提前準(zhǔn)備好的代碼塊,在需要的時(shí)候執(zhí)行
  • 隊(duì)列:
    • 串行隊(duì)列:一個(gè)接一個(gè)的調(diào)度任務(wù)
    • 并發(fā)隊(duì)列:可以同時(shí)調(diào)度多個(gè)任務(wù)
    • 主隊(duì)列: 專門用來在主線程上調(diào)度任務(wù)的"隊(duì)列"
      主隊(duì)列不能在其他線程中調(diào)度任務(wù)!
      如果主線程上當(dāng)前正在有執(zhí)行的任務(wù),主隊(duì)列暫時(shí)不會(huì)調(diào)度任務(wù)的執(zhí)行!
      注意:主隊(duì)列不是主線程
      • 異步任務(wù),會(huì)在主線程的方法執(zhí)行完成后,被調(diào)度
      • 同步任務(wù),會(huì)造成死鎖
    • 全局隊(duì)列,系統(tǒng)提供給程序員,方便程序員使用的全局隊(duì)列
      有關(guān)服務(wù)質(zhì)量問題,使用以下代碼能夠做到 iOS7 & iOS8 的適配
      dispatch_get_global_queue(0, 0);
  • 執(zhí)行任務(wù)的函數(shù)
    • 同步執(zhí)行:當(dāng)前指令不完成,就不會(huì)執(zhí)行下一條指令
    • 異步執(zhí)行:當(dāng)前指令不完成,同樣可以執(zhí)行下一條指令
      異步是多線程的代名詞
  • 小結(jié):
    • 開不開線程,取決于執(zhí)行任務(wù)的函數(shù),同步不開,異步開
    • 開幾條線程,取決于隊(duì)列,串行開一條,并發(fā)開多條(異步)

3、GCD的基本使用

GCD的基本使用步驟有兩步:

1、創(chuàng)建一個(gè)隊(duì)列。
2、將任務(wù)添加到隊(duì)列中,然后系統(tǒng)就會(huì)根據(jù)任務(wù)類型執(zhí)行任務(wù)。(同步執(zhí)行或異步執(zhí)行)

串形隊(duì)列+同步執(zhí)行

不會(huì)開線程,會(huì)順序執(zhí)行

    // 1. 隊(duì)列
    /**
     參數(shù)
     1. 隊(duì)列的名稱
     2. 隊(duì)列的屬性 
        DISPATCH_QUEUE_SERIAL(NULL) 表示串行
     */
    dispatch_queue_t q = dispatch_queue_create("com.chenhuan.queue", DISPATCH_QUEUE_SERIAL);
    
    NSLog(@"start");
    // 2. 執(zhí)行任務(wù)
    for (int i = 0; i < 10; i++) {
        dispatch_sync(q, ^{
            NSLog(@"%@ %d", [NSThread currentThread], i);
        });
    }
    NSLog(@"end");

輸出結(jié)果

2017-07-29 19:08:27.030 Demo-GCD[942:62206] start
2017-07-29 19:08:27.030 Demo-GCD[942:62206] <NSThread: 0x61800007eac0>{number = 1, name = main} 0
2017-07-29 19:08:27.031 Demo-GCD[942:62206] <NSThread: 0x61800007eac0>{number = 1, name = main} 1
2017-07-29 19:08:27.031 Demo-GCD[942:62206] <NSThread: 0x61800007eac0>{number = 1, name = main} 2
2017-07-29 19:08:27.031 Demo-GCD[942:62206] <NSThread: 0x61800007eac0>{number = 1, name = main} 3
2017-07-29 19:08:27.031 Demo-GCD[942:62206] <NSThread: 0x61800007eac0>{number = 1, name = main} 4
2017-07-29 19:08:27.031 Demo-GCD[942:62206] <NSThread: 0x61800007eac0>{number = 1, name = main} 5
2017-07-29 19:08:27.032 Demo-GCD[942:62206] <NSThread: 0x61800007eac0>{number = 1, name = main} 6
2017-07-29 19:08:27.032 Demo-GCD[942:62206] <NSThread: 0x61800007eac0>{number = 1, name = main} 7
2017-07-29 19:08:27.032 Demo-GCD[942:62206] <NSThread: 0x61800007eac0>{number = 1, name = main} 8
2017-07-29 19:08:27.032 Demo-GCD[942:62206] <NSThread: 0x61800007eac0>{number = 1, name = main} 9
2017-07-29 19:08:27.032 Demo-GCD[942:62206] end
  • 串行隊(duì)列 + 同步執(zhí)行可以看到,所有任務(wù)都是在主線程中執(zhí)行的,并沒有開啟新的線程。而且由于串行隊(duì)列,所以按順序一個(gè)一個(gè)執(zhí)行。
  • 所有任務(wù)都在打印的startend之間,這說明任務(wù)是添加到隊(duì)列中馬上執(zhí)行的。

串形隊(duì)列+異步執(zhí)行

會(huì)開啟新的線程,一個(gè)一個(gè)順序執(zhí)行

    dispatch_queue_t q = dispatch_queue_create("com.chenhuan.queue", NULL);
    NSLog(@"start");
    for (int i = 0; i<10; i++) {
        dispatch_async(q, ^{
            NSLog(@"%@ %d", [NSThread currentThread], i);
        });
    }
    NSLog(@"end");

輸出結(jié)果

2017-07-29 19:40:35.466 08-GCD演練[988:72561] start
2017-07-29 19:40:35.466 08-GCD演練[988:72561] end
2017-07-29 19:40:35.466 08-GCD演練[988:72613] <NSThread: 0x610000072b00>{number = 3, name = (null)} 0
2017-07-29 19:40:35.467 08-GCD演練[988:72613] <NSThread: 0x610000072b00>{number = 3, name = (null)} 1
2017-07-29 19:40:35.467 08-GCD演練[988:72613] <NSThread: 0x610000072b00>{number = 3, name = (null)} 2
2017-07-29 19:40:35.467 08-GCD演練[988:72613] <NSThread: 0x610000072b00>{number = 3, name = (null)} 3
2017-07-29 19:40:35.467 08-GCD演練[988:72613] <NSThread: 0x610000072b00>{number = 3, name = (null)} 4
2017-07-29 19:40:35.467 08-GCD演練[988:72613] <NSThread: 0x610000072b00>{number = 3, name = (null)} 5
2017-07-29 19:40:35.468 08-GCD演練[988:72613] <NSThread: 0x610000072b00>{number = 3, name = (null)} 6
2017-07-29 19:40:35.468 08-GCD演練[988:72613] <NSThread: 0x610000072b00>{number = 3, name = (null)} 7
2017-07-29 19:40:35.468 08-GCD演練[988:72613] <NSThread: 0x610000072b00>{number = 3, name = (null)} 8
2017-07-29 19:40:35.468 08-GCD演練[988:72613] <NSThread: 0x610000072b00>{number = 3, name = (null)} 9
  • 串形隊(duì)列+異步執(zhí)行可以看到,會(huì)開啟一條新的線程,并且一個(gè)一個(gè)執(zhí)行
  • 所有任務(wù)是在打印的startend之后才開始執(zhí)行的。說明任務(wù)不是馬上執(zhí)行,而是將所有任務(wù)添加到隊(duì)列之后才開始同步執(zhí)行。

并發(fā)隊(duì)列+同步執(zhí)行

不會(huì)開啟線程,并且順序執(zhí)行

    // 1. 隊(duì)列
    dispatch_queue_t q = dispatch_queue_create("com.chenhuan.queue", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"start");
    // 2. 異步執(zhí)行
    for (int i = 0; i<10; i++) {
        dispatch_sync(q, ^{
            NSLog(@"%@ %d", [NSThread currentThread], i);
        });
    }
    NSLog(@"end");

輸出結(jié)果

2017-07-29 20:38:10.211 Demo-GCD[1125:109556] start
2017-07-29 20:38:10.212 Demo-GCD[1125:109556] <NSThread: 0x60800007a9c0>{number = 1, name = main} 0
2017-07-29 20:38:10.212 Demo-GCD[1125:109556] <NSThread: 0x60800007a9c0>{number = 1, name = main} 1
2017-07-29 20:38:10.212 Demo-GCD[1125:109556] <NSThread: 0x60800007a9c0>{number = 1, name = main} 2
2017-07-29 20:38:10.212 Demo-GCD[1125:109556] <NSThread: 0x60800007a9c0>{number = 1, name = main} 3
2017-07-29 20:38:10.213 Demo-GCD[1125:109556] <NSThread: 0x60800007a9c0>{number = 1, name = main} 4
2017-07-29 20:38:10.213 Demo-GCD[1125:109556] <NSThread: 0x60800007a9c0>{number = 1, name = main} 5
2017-07-29 20:38:10.213 Demo-GCD[1125:109556] <NSThread: 0x60800007a9c0>{number = 1, name = main} 6
2017-07-29 20:38:10.213 Demo-GCD[1125:109556] <NSThread: 0x60800007a9c0>{number = 1, name = main} 7
2017-07-29 20:38:10.213 Demo-GCD[1125:109556] <NSThread: 0x60800007a9c0>{number = 1, name = main} 8
2017-07-29 20:38:10.214 Demo-GCD[1125:109556] <NSThread: 0x60800007a9c0>{number = 1, name = main} 9
2017-07-29 20:38:10.214 Demo-GCD[1125:109556] end
  • 并發(fā)隊(duì)列 + 同步執(zhí)行可以看到,所有任務(wù)都是在主線程中執(zhí)行的,并沒有開啟新的線程。而且都是按順序一個(gè)一個(gè)執(zhí)行。
  • 所有任務(wù)都在打印的startend之間,這說明任務(wù)是添加到隊(duì)列中馬上執(zhí)行的。

并發(fā)隊(duì)列+異步執(zhí)行

會(huì)開啟多條線程,并且交替執(zhí)行

    // 1. 隊(duì)列
    dispatch_queue_t q = dispatch_queue_create("com.chenhuan.queue", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"start");
    // 2. 異步執(zhí)行
    for (int i = 0; i<10; i++) {
        dispatch_async(q, ^{
            NSLog(@"%@ %d", [NSThread currentThread], i);
        });
    }
    NSLog(@"end");

輸出結(jié)果

2017-07-29 20:36:52.573 Demo-GCD[1100:104147] start
2017-07-29 20:36:52.573 Demo-GCD[1100:104147] end
2017-07-29 20:36:52.573 Demo-GCD[1100:107782] <NSThread: 0x610000264e00>{number = 20, name = (null)} 0
2017-07-29 20:36:52.573 Demo-GCD[1100:108095] <NSThread: 0x618000262b40>{number = 39, name = (null)} 1
2017-07-29 20:36:52.574 Demo-GCD[1100:108096] <NSThread: 0x610000264f40>{number = 40, name = (null)} 2
2017-07-29 20:36:52.574 Demo-GCD[1100:108097] <NSThread: 0x60800026a200>{number = 41, name = (null)} 3
2017-07-29 20:36:52.574 Demo-GCD[1100:108099] <NSThread: 0x60800026a300>{number = 42, name = (null)} 4
2017-07-29 20:36:52.574 Demo-GCD[1100:108102] <NSThread: 0x610000266c40>{number = 43, name = (null)} 5
2017-07-29 20:36:52.574 Demo-GCD[1100:108100] <NSThread: 0x600000264d80>{number = 45, name = (null)} 7
2017-07-29 20:36:52.574 Demo-GCD[1100:108104] <NSThread: 0x600000264c00>{number = 44, name = (null)} 6
2017-07-29 20:36:52.574 Demo-GCD[1100:108106] <NSThread: 0x60800026a280>{number = 46, name = (null)} 8
2017-07-29 20:36:52.574 Demo-GCD[1100:108107] <NSThread: 0x60800026a2c0>{number = 47, name = (null)} 9

  • 并發(fā)隊(duì)列 + 異步執(zhí)行可以看到,所有任務(wù)都是在異步線程中執(zhí)行。并且任務(wù)是交替著同時(shí)執(zhí)行的。
  • 所有任務(wù)都在打印的startend之間,這說明任務(wù)是添加到隊(duì)列中馬上執(zhí)行的。

主隊(duì)列+同步執(zhí)行

不要這樣干,會(huì)造成死鎖

    dispatch_queue_t q = dispatch_get_main_queue();
    
    NSLog(@"卡死了嗎?");
    
    dispatch_sync(q, ^{
        NSLog(@"我來了");
    });
    
    NSLog(@"come here");

輸出結(jié)果

2017-07-29 21:13:23.550 Demo-GCD[1148:120053] 卡死了嗎?
  • 如果你自己運(yùn)行以上代碼,會(huì)發(fā)現(xiàn)程序不能運(yùn)行了。這是因?yàn)檎粘闪怂梨i
  • 我們知道dispatch_sync表示同步的執(zhí)行任務(wù),也就是說執(zhí)行dispatch_sync后,當(dāng)前隊(duì)列會(huì)阻塞。而dispatch_sync中的block如果要在當(dāng)前隊(duì)列中執(zhí)行,就得等待當(dāng)前隊(duì)列程執(zhí)行完成。
  • 在上面這個(gè)例子中,主隊(duì)列在執(zhí)行dispatch_sync,隨后隊(duì)列中新增一個(gè)任務(wù)block。因?yàn)橹麝?duì)列是同步隊(duì)列,所以block要等dispatch_sync執(zhí)行完才能執(zhí)行,但是dispatch_sync是同步派發(fā),要等block執(zhí)行完才算是結(jié)束。在主隊(duì)列中的兩個(gè)任務(wù)互相等待,導(dǎo)致了死鎖。

主隊(duì)列+異步執(zhí)行

    // 1. 主隊(duì)列 - 程序啟動(dòng)之后已經(jīng)存在主線程,主隊(duì)列同樣存在
    dispatch_queue_t q = dispatch_get_main_queue();
    
    // 2. 安排一個(gè)任務(wù)
    for (int i = 0; i<10; i++) {
        dispatch_async(q, ^{
            NSLog(@"%@ %d", [NSThread currentThread], i);
        });
    }
    
    NSLog(@"睡會(huì)");
    [NSThread sleepForTimeInterval:2.0];
    NSLog(@"come here");

輸出結(jié)果

2017-07-29 21:21:30.547 Demo-GCD[1208:127513] 睡會(huì)
2017-07-29 21:21:32.548 Demo-GCD[1208:127513] come here
2017-07-29 21:21:32.548 Demo-GCD[1208:127513] <NSThread: 0x600000076d40>{number = 1, name = main} 0
2017-07-29 21:21:32.548 Demo-GCD[1208:127513] <NSThread: 0x600000076d40>{number = 1, name = main} 1
2017-07-29 21:21:32.549 Demo-GCD[1208:127513] <NSThread: 0x600000076d40>{number = 1, name = main} 2
2017-07-29 21:21:32.549 Demo-GCD[1208:127513] <NSThread: 0x600000076d40>{number = 1, name = main} 3
2017-07-29 21:21:32.549 Demo-GCD[1208:127513] <NSThread: 0x600000076d40>{number = 1, name = main} 4
2017-07-29 21:21:32.550 Demo-GCD[1208:127513] <NSThread: 0x600000076d40>{number = 1, name = main} 5
2017-07-29 21:21:32.550 Demo-GCD[1208:127513] <NSThread: 0x600000076d40>{number = 1, name = main} 6
2017-07-29 21:21:32.550 Demo-GCD[1208:127513] <NSThread: 0x600000076d40>{number = 1, name = main} 7
2017-07-29 21:21:32.550 Demo-GCD[1208:127513] <NSThread: 0x600000076d40>{number = 1, name = main} 8
2017-07-29 21:21:32.551 Demo-GCD[1208:127513] <NSThread: 0x600000076d40>{number = 1, name = main} 9
  • 不開線程,順序執(zhí)行
  • 從上面可以看出,異步執(zhí)行不會(huì)阻塞線程

全局隊(duì)列

    /**
     參數(shù)
     1. 涉及到系統(tǒng)適配
     iOS 8       服務(wù)質(zhì)量(讓線程響應(yīng)的更快還是更慢)
     - QOS_CLASS_USER_INTERACTIVE           用戶交互(用戶迫切希望線程快點(diǎn)被執(zhí)行,不要用耗時(shí)的操作)
     - QOS_CLASS_USER_INITIATED             用戶需要的(同樣不要使用耗時(shí)操作)
     - QOS_CLASS_DEFAULT                    默認(rèn)的(給系統(tǒng)用來重置隊(duì)列的)
     ** QOS_CLASS_UTILITY                    實(shí)用工具(用來做耗時(shí)操作)
     - QOS_CLASS_BACKGROUND                 后臺(tái)
     - QOS_CLASS_UNSPECIFIED                沒有指定優(yōu)先級(jí)
     
     iOS 7       調(diào)度的優(yōu)先級(jí)
     - DISPATCH_QUEUE_PRIORITY_HIGH 2       高優(yōu)先級(jí)
     - DISPATCH_QUEUE_PRIORITY_DEFAULT 0    默認(rèn)優(yōu)先級(jí)
     - DISPATCH_QUEUE_PRIORITY_LOW (-2)     低優(yōu)先級(jí)
     - DISPATCH_QUEUE_PRIORITY_BACKGROUND   后臺(tái)優(yōu)先級(jí)
     
     提示:尤其不要選擇 BACKGROUND 優(yōu)先級(jí)和服務(wù)質(zhì)量,用戶不需要知道線程什么時(shí)候執(zhí)行完成!線程的執(zhí)行會(huì)慢的令人發(fā)指!
     
     有關(guān)服務(wù)質(zhì)量的介紹,用在與 XPC 框架結(jié)合使用的,XPC 用在 MAC 平臺(tái)上做進(jìn)程間通訊的框架!
     
     因?yàn)榇蠹夜ぷ骱?,暫時(shí)會(huì)考慮 iOS7 & iOS8 的適配,無法使用服務(wù)質(zhì)量,直接指定 0,能夠做到 iOS7 & 8 的適配
     dispatch_get_global_queue(0, 0);
     
     2. 為未來使用保留的,應(yīng)該始終傳入0
     */
    dispatch_queue_t q = dispatch_get_global_queue(0, 0);
    
    for (int i = 0; i < 10; i++) {
        dispatch_async(q, ^{
            NSLog(@"%@ %d", [NSThread currentThread], i);
        });
    }
    NSLog(@"com here");

  • 全局隊(duì)列可以當(dāng)作并發(fā)隊(duì)列來使用。一般我們?cè)陂_發(fā)過程中都是使用global_queue

4、GCD的其他一些用法

dispatch_group

在實(shí)際開發(fā)中,有的時(shí)候,會(huì)需要同時(shí)監(jiān)聽多個(gè)異步任務(wù)最終完成的情況!這個(gè)時(shí)候就需要用到我們的 dispatch_group

  // 1. 隊(duì)列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    // 2. 調(diào)度組
    dispatch_group_t group = dispatch_group_create();
    
    // 3. 添加任務(wù),讓隊(duì)列調(diào)度,指定任務(wù)執(zhí)行函數(shù),最終通知群組
    dispatch_group_async(group, queue, ^{
        NSLog(@"download A %@", [NSThread currentThread]);
    });
    dispatch_group_async(group, queue, ^{
        [NSThread sleepForTimeInterval:1.0];
        NSLog(@"download B %@", [NSThread currentThread]);
    });
    dispatch_group_async(group, queue, ^{
        [NSThread sleepForTimeInterval:0.8];
        NSLog(@"download C %@", [NSThread currentThread]);
    });
    
    // 4. 所有任務(wù)執(zhí)行完畢后,獲得通知
    // 用一個(gè)調(diào)度組,可以監(jiān)聽全局隊(duì)列調(diào)度的任務(wù),執(zhí)行完畢后,在主隊(duì)列執(zhí)行最終處理!
    // dispatch_group_notify 本身是異步的
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        // 更新UI,通知用戶!
        NSLog(@"OK %@", [NSThread currentThread]);
    });
    
    NSLog(@"come here");

輸出結(jié)果

2017-07-29 21:31:18.362 Demo-GCD[1255:135674] come here
2017-07-29 21:31:18.362 Demo-GCD[1255:135726] download A <NSThread: 0x60000006e040>{number = 3, name = (null)}
2017-07-29 21:31:19.166 Demo-GCD[1255:135723] download C <NSThread: 0x60000006b200>{number = 4, name = (null)}
2017-07-29 21:31:19.362 Demo-GCD[1255:135741] download B <NSThread: 0x60000006fd80>{number = 5, name = (null)}
2017-07-29 21:31:19.363 Demo-GCD[1255:135674] OK <NSThread: 0x60800006c540>{number = 1, name = main}

首先我們要通過 dispatch_group_create() 方法生成一個(gè)組。

接下來,我們把 dispatch_async 方法換成 dispatch_group_async。這個(gè)方法多了一個(gè)參數(shù),第一個(gè)參數(shù)填剛剛創(chuàng)建的分組。

最后調(diào)用 dispatch_group_notify 方法。這個(gè)方法表示把第三個(gè)參數(shù) block 傳入第二個(gè)參數(shù)隊(duì)列中去。而且可以保證第三個(gè)參數(shù) block 執(zhí)行時(shí),group 中的所有任務(wù)已經(jīng)全部完成。

dispatch_group 第二種調(diào)用方式

    // 1. 隊(duì)列
    dispatch_queue_t q = dispatch_get_global_queue(0, 0);
    
    // 2. 調(diào)度組
    dispatch_group_t g = dispatch_group_create();
    
    // 3. 進(jìn)入群組,執(zhí)行此函數(shù)后,再添加的異步執(zhí)行的block,會(huì)被group監(jiān)聽
    // dispatch_group_enter & dispatch_group_leave一定要配對(duì)出現(xiàn)
    dispatch_group_enter(g);
    
    // 4. 添加任務(wù)
    dispatch_async(q, ^{
        [NSThread sleepForTimeInterval:10.0];
        NSLog(@"download A");
        // 異步任務(wù)中,所有的代碼執(zhí)行完畢后,最后離開群組
        dispatch_group_leave(g);
    });
    
    // 再次添加任務(wù)
    dispatch_group_enter(g);
    
    // 5. 添加任務(wù) B
    dispatch_async(q, ^{
        NSLog(@"download B");
        // 異步任務(wù)中,所有的代碼執(zhí)行完畢后,最后離開群組
        dispatch_group_leave(g);
    });
    
//     6. 攔截通知
//        dispatch_group_notify(g, q, ^{
//            NSLog(@"Over");
//        });
    // 等待到永遠(yuǎn),死等,阻塞住線程執(zhí)行,一直到所有的任務(wù)執(zhí)行完畢,才會(huì)執(zhí)行后續(xù)的代碼!
    long time = dispatch_group_wait(g, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)));
    
    NSLog(@"result=%ld",time);
    NSLog(@"come here");

輸出結(jié)果

2017-07-29 21:52:08.123 Demo-GCD[1326:154377] download B
2017-07-29 21:52:10.124 Demo-GCD[1326:154323] result=49
2017-07-29 21:52:10.124 Demo-GCD[1326:154323] come here
2017-07-29 21:52:18.126 Demo-GCD[1326:154391] download A

dispatch_group_wait 方法是一個(gè)很有用的方法,它的完整定義如下:

long dispatch_group_wait(dispatch_group_t group, dispatch_time_t timeout);

第一個(gè)參數(shù)表示要等待的 group,第二個(gè)則表示等待時(shí)間。返回值表示經(jīng)過指定的等待時(shí)間,屬于這個(gè) group 的任務(wù)是否已經(jīng)全部執(zhí)行完,如果是則返回 0,否則返回非 0。

第二個(gè) dispatch_time_t 類型的參數(shù)還有兩個(gè)特殊值:DISPATCH_TIME_NOWDISPATCH_TIME_FOREVER

前者表示立刻檢查屬于這個(gè) group 的任務(wù)是否已經(jīng)完成,后者則表示一直等到屬于這個(gè) group 的任務(wù)全部完成。

dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC))傳入這個(gè)參數(shù)表示等待兩秒后檢查執(zhí)行情況。顯然沒有執(zhí)行完成 result=49

dispatch_after

通過 GCD 還可以進(jìn)行簡(jiǎn)單的定時(shí)操作,比如在 3 秒后執(zhí)行某個(gè) block 。代碼如下:

    NSLog(@"come here");
    
    /**
     參數(shù):
     從現(xiàn)在開始,經(jīng)過多少納秒之后,讓 queue 隊(duì)列,調(diào)度 block 任務(wù),異步執(zhí)行!
     
     1. when
     2. queue
     3. block
    // 從現(xiàn)在開始,經(jīng)過多少納秒之后
    dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC));
    
    // 主隊(duì)列
//    dispatch_after(when, dispatch_get_main_queue(), ^{
//        NSLog(@"%@", [NSThread currentThread]);
//    });
    // 全局隊(duì)列
//    dispatch_after(when, dispatch_get_global_queue(0, 0), ^{
//        NSLog(@"%@", [NSThread currentThread]);
//    });
    // 串行隊(duì)列
    dispatch_after(when, dispatch_queue_create("com.chenhuan.queue", NULL), ^{
        NSLog(@"%@", [NSThread currentThread]);
    });

dispatch_after 方法有三個(gè)參數(shù)。第一個(gè)表示時(shí)間,也就是從現(xiàn)在起往后三秒鐘。第二、三個(gè)參數(shù)分別表示要提交的任務(wù)和提交到哪個(gè)隊(duì)列。

dispatch_once

dispathc_once 函數(shù)可以確保某個(gè) block 在應(yīng)用程序執(zhí)行的過程中只被處理一次,而且它是線程安全的。所以單例模式可以很簡(jiǎn)單的實(shí)現(xiàn),以 OC 中單例類為例

+ (instancetype)sharedInstance {
    static id instance = nil;
    static dispatch_once_t once;
    dispatch_once($once, ^{
        instance = [[self alloc] init];
    });

    return sharedManagerInstance;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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