OC高級(jí)-GCD使用總結(jié)

GCD簡(jiǎn)介

  • GCD全稱:Grand Central Dispatch,譯為大型的中樞調(diào)度器
  • 純C語(yǔ)言實(shí)現(xiàn),提供了非常多強(qiáng)大的功能
  • GCD的優(yōu)勢(shì)
    • GCD是蘋(píng)果公司為多核的并行運(yùn)算提出的解決方案
    • GCD會(huì)自動(dòng)利用更多的CPU內(nèi)核(如:雙核、四核)
    • GCD會(huì)自動(dòng)管理線程的生命周期(創(chuàng)建線程、調(diào)度任務(wù)、銷毀線程)
    • 程序猿只需要告訴GCD想要執(zhí)行什么任務(wù),不需要編寫(xiě)任何管理線程的代碼
  • GCD的兩個(gè)核心概念:任務(wù)隊(duì)列
    • 任務(wù):執(zhí)行什么操作
    • 隊(duì)列:用來(lái)存放任務(wù),分為:并行隊(duì)列和串行隊(duì)列

并行隊(duì)列 串行隊(duì)列

  • 隊(duì)列本質(zhì):用于控制任務(wù)的執(zhí)行方式
  • 并行隊(duì)列
    • 英文:Concurrent Dispatch Queue
    • 可以讓多個(gè)任務(wù)并發(fā)執(zhí)行,以提高執(zhí)行效率
    • 并發(fā)功能異步(dispatch_async)函數(shù)下才有效
  • 串行隊(duì)列
    • 英文:Serial Dispatch Queue
    • 在當(dāng)前線程中讓任務(wù)一個(gè)接著一個(gè)地執(zhí)行
  • 創(chuàng)建隊(duì)列
// 隊(duì)列類型
dispatch_queue_t

// 第一個(gè)參數(shù):隊(duì)列名稱
// 第二個(gè)參數(shù):隊(duì)列類型
dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);

/** 隊(duì)列類型
  // 串行隊(duì)列標(biāo)識(shí):本質(zhì)就是NULL,但建議不要寫(xiě)成NULL,可讀性不好
  DISPATCH_QUEUE_SERIAL
  // 并行隊(duì)列標(biāo)識(shí)
  DISPATCH_QUEUE_CONCURRENT
*/
  • 創(chuàng)建并行隊(duì)列的兩種方式
    • 直接創(chuàng)建
    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_CONCURRENT);
    
    • 獲取全局并發(fā)隊(duì)列
    // 第一個(gè)參數(shù):隊(duì)列優(yōu)先級(jí)
    // 第二個(gè)參數(shù):保留參數(shù),暫時(shí)無(wú)用,用0即可
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    // 全局并發(fā)隊(duì)列的優(yōu)先級(jí)
    #define DISPATCH_QUEUE_PRIORITY_HIGH 2               // 高
    #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0            // 默認(rèn)(中)
    #define DISPATCH_QUEUE_PRIORITY_LOW (-2)             // 低
    #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后臺(tái)
    
  • 創(chuàng)建串行隊(duì)列的兩種方式
    • 直接創(chuàng)建
    // 創(chuàng)建串行隊(duì)列(隊(duì)列類型傳遞DISPATCH_QUEUE_SERIAL或者NULL)
    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_SERIAL);
    
    • 獲取主隊(duì)列:主隊(duì)列是一種特殊的串行隊(duì)列
    // 主隊(duì)列中的任務(wù),都會(huì)放到主線程中執(zhí)行
    dispatch_queue_t queue = dispatch_get_main_queue();
    

同步(sync)函數(shù) 異步(async)函數(shù)

  • 函數(shù)作用:將任務(wù)添加到隊(duì)列
  • 函數(shù)類型:決定是否有開(kāi)啟新線程的能力
  • 同步函數(shù):不具備開(kāi)啟新線程的能力,只能在當(dāng)前線程中執(zhí)行任務(wù)
// queue:隊(duì)列
// block:任務(wù)
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
  • 異步函數(shù):具備開(kāi)啟線程的能力,但不一定開(kāi)啟新線程,比如:當(dāng)前隊(duì)列為主隊(duì)列,異步函數(shù)也不會(huì)開(kāi)啟新的線程
// queue:隊(duì)列
// block:任務(wù)
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
  • 經(jīng)驗(yàn)總結(jié):
    • 通過(guò)異步函數(shù)添加任務(wù)到隊(duì)列中,任務(wù)不會(huì)立即執(zhí)行
    • 通過(guò)同步函數(shù)添加任務(wù)到隊(duì)列中,任務(wù)會(huì)立即執(zhí)行

程序猿只需要做下列事情

  • 指定函數(shù)類型:是否具備開(kāi)啟新線程的能力
  • 指定隊(duì)列類型:決定任務(wù)的執(zhí)行方式
  • 確定要執(zhí)行的任務(wù),并通過(guò)函數(shù)任務(wù)添加到隊(duì)列中,任務(wù)的執(zhí)行遵循隊(duì)列的FIFO原則:先進(jìn)先出,后進(jìn)后出
  • 剩下的事情就交給GCD來(lái)完成了

函數(shù)和隊(duì)列組合后的執(zhí)行效果

Thread_3.png
  • 異步函數(shù) + 并行隊(duì)列
    • 開(kāi)啟多條子線程,任務(wù)并行執(zhí)行
    • 代碼展示
- (void)asyncConcurrent
{
    // 1.創(chuàng)建并行隊(duì)列
//    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    // 2.通過(guò)異步函數(shù)將將任務(wù)加入隊(duì)列
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<10; i++) {
            NSLog(@"1-----%@", [NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<10; i++) {
            NSLog(@"2-----%@", [NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<10; i++) {
            NSLog(@"3-----%@", [NSThread currentThread]);
        }
    });

    // 證明:異步函數(shù)添加任務(wù)到隊(duì)列中,任務(wù)【不會(huì)】立即執(zhí)行
    NSLog(@"asyncConcurrent--------end");

    // 釋放隊(duì)列,ARC中無(wú)需也不允許調(diào)用這個(gè)方法
//    dispatch_release(queue);
}
  • 異步函數(shù) + 串行隊(duì)列
    • 開(kāi)啟一條子線程,任務(wù)是有序的在子線程上執(zhí)行
    • 代碼展示
- (void)asyncSerial
{
    // 1.創(chuàng)建串行隊(duì)列
    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_SERIAL);
//    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", NULL);

    // 2.通過(guò)異步函數(shù)將任務(wù)加入隊(duì)列
    dispatch_async(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });

    // 證明:異步函數(shù)添加任務(wù)到隊(duì)列中,任務(wù)【不會(huì)】立馬執(zhí)行
    NSLog(@"asyncConcurrent--------end");
}
  • 異步函數(shù) + 主隊(duì)列
    • 不開(kāi)啟子線程,任務(wù)是在主線程中有序執(zhí)行
    • 代碼展示
- (void)asyncMain
{
    // 1.獲得主隊(duì)列
    dispatch_queue_t queue = dispatch_get_main_queue();

    // 2.通過(guò)異步函數(shù)將任務(wù)加入隊(duì)列
    dispatch_async(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });
}
  • 同步函數(shù) + 并行隊(duì)列
    • 不會(huì)開(kāi)啟子線程,任務(wù)是有序執(zhí)行
    • 代碼展示
- (void)syncConcurrent
{
    // 1.獲得全局的并發(fā)隊(duì)列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    // 2.通過(guò)同步函數(shù)將任務(wù)加入隊(duì)列
    dispatch_sync(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });

    // 證明:同步函數(shù)添加任務(wù)到隊(duì)列中,任務(wù)【立馬執(zhí)行】
    NSLog(@"syncConcurrent--------end");
}
  • 同步函數(shù) + 串行隊(duì)列
    • 不會(huì)開(kāi)啟線程,任務(wù)是有序執(zhí)行
    • 易發(fā)生死鎖,使用時(shí)要注意
    • 下面的用法會(huì)發(fā)生死鎖嗎?
- (void)syncMain
{
    // 1.創(chuàng)建串行隊(duì)列
    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_SERIAL);

    // 2.將任務(wù)加入隊(duì)列
    dispatch_sync(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });
}
  • 答案:上面的用法不會(huì)發(fā)生死鎖,原因分析如下:
    • 雖然都是在主線程上執(zhí)行的,但任務(wù)在不同的隊(duì)列中所以不會(huì)發(fā)生阻塞
    • syncMain函數(shù)是在主隊(duì)列中
    • 其他的任務(wù)是在新建的串行隊(duì)列
  • 死鎖的幾中場(chǎng)景
    • 場(chǎng)景1
    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
           NSLog(@"1-----%@", [NSThread currentThread]);
    
           // 這里阻塞了
           dispatch_sync(queue, ^{
                 NSLog(@"2-----%@", [NSThread currentThread]);
           });
    });
    
    • 場(chǎng)景2
      - (void)syncMain
      {
          // 獲得主隊(duì)列
          dispatch_queue_t queue = dispatch_get_main_queue();
    
          // 這里阻塞了
          dispatch_sync(queue, ^{
              NSLog(@"1-----%@", [NSThread currentThread]);
          });
          dispatch_sync(queue, ^{
              NSLog(@"2-----%@", [NSThread currentThread]);
          });
          dispatch_sync(queue, ^{
              NSLog(@"3-----%@", [NSThread currentThread]);
          });
      }
    
    • 原因分析
      • 使用同步函數(shù)在任務(wù)執(zhí)行過(guò)程中往任務(wù)所在的串行隊(duì)列中添加任務(wù)就會(huì)導(dǎo)致任務(wù)間互相等待,造成死鎖
      • 別忘了同步函數(shù)添加任務(wù)到隊(duì)列中,任務(wù)會(huì)立即執(zhí)行,如果是異步函數(shù)不會(huì)發(fā)生死鎖

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

// 全局并發(fā)隊(duì)列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 異步函數(shù)
dispatch_async(queue, ^
{
        // 執(zhí)行耗時(shí)的任務(wù)
        coding...

        // 【標(biāo)記1】回到主線程,執(zhí)行UI刷新操作
        dispatch_async(dispatch_get_main_queue(), ^
        {
            coding...

            // 還可以嵌套:再回到子線程做其他事情
            dispatch_async(queue, ^
            {
                coding...
            });
        });

        // 后續(xù)代碼
        coding....
});
  • 【標(biāo)記1】處也可以用同步函數(shù)回到主線程,但是同步函數(shù)會(huì)導(dǎo)致添加的新任務(wù)立即執(zhí)行,導(dǎo)致必須等添加到主隊(duì)列的任務(wù)執(zhí)行完才會(huì)繼續(xù)執(zhí)行,也不是不能這么用,看具體場(chǎng)景是否需要等待主隊(duì)列的任務(wù)執(zhí)行完畢才繼續(xù)往后執(zhí)行

GCD中其他常用函數(shù)

dispatch_once_t

  • 函數(shù)作用:保證某段代碼在程序運(yùn)行過(guò)程中只被執(zhí)行1次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    // 只執(zhí)行1次的代碼(這個(gè)函數(shù)本身是【線程安全】的)
});

dispatch_after和dispatch_time_t

  • 函數(shù)作用:延遲將任務(wù)提交到隊(duì)列中,不要理解成延遲執(zhí)行任務(wù)
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC));
dispatch_after(time, queue, ^
{
    // 此任務(wù)被延遲提交到隊(duì)列中
});
  • dispatch_time_t
    • 第一個(gè)參數(shù)一般是DISPATCH_TIME_NOW,表示從現(xiàn)在開(kāi)始
    • 第二個(gè)參數(shù)就是真正的延時(shí)時(shí)間,單位為納秒
    • 關(guān)于NSEC_PER_SEC的解釋可以查看我這篇文章

dispatch_suspend 和 dispatch_resume

  • dispatch_suspend
    • 函數(shù)作用:只能掛起隊(duì)列中還未執(zhí)行的任務(wù),正在運(yùn)行的任務(wù)是無(wú)法掛起的
  • dispatch_resume
    • 函數(shù)作用:只能恢復(fù)隊(duì)列中還未執(zhí)行的任務(wù)

dispatch_apply

  • 此函數(shù)和dispatch_sync函數(shù)一樣,會(huì)等待處理結(jié)束,所以建議在dispatch_async中使用此函數(shù)
  • 此函數(shù)必須結(jié)合并行隊(duì)列才能發(fā)揮作用
  • 函數(shù)作用:可以快速完成對(duì)順序沒(méi)有要求的集合遍歷,因?yàn)?code>執(zhí)行順序不確定
  • 使用說(shuō)明
dispatch_apply(10, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index)
{
    // 執(zhí)行10次代碼,會(huì)開(kāi)啟多條線程來(lái)執(zhí)行任務(wù),執(zhí)行順序不確定
});
  • 示例:文件剪切
- (void)applyDemo
{
    NSString *from = @"/Users/xxx/Desktop/From";
    NSString *to = @"/Users/xxx/Desktop/To";

    NSFileManager *mgr = [NSFileManager defaultManager];
    NSArray *subpaths = [mgr subpathsAtPath:from];

    // 并行隊(duì)列才會(huì)起作用
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_apply(subpaths.count, queue, ^(size_t index) {
        NSString *subpath = subpaths[index];
        NSString *fromFullpath = [from stringByAppendingPathComponent:subpath];
        NSString *toFullpath = [to stringByAppendingPathComponent:subpath];
        // 剪切
        [mgr moveItemAtPath:fromFullpath toPath:toFullpath error:nil];

        NSLog(@"%@---%@", [NSThread currentThread], subpath);
    });
}

dispatch_barrier_async

  • 必須并行隊(duì)列,且不能使用全局的并行隊(duì)列,實(shí)踐證明不管用
  • 函數(shù)作用:在此函數(shù)前面的任務(wù)執(zhí)行完成后此函數(shù)才開(kāi)始執(zhí)行,在此函數(shù)后面的任務(wù)等此函數(shù)執(zhí)行完成后才會(huì)執(zhí)行
- (void)barrierDemo
{
    //【不能】使用全局并發(fā)隊(duì)列
    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(queue, ^{
        NSLog(@"----1-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"----2-----%@", [NSThread currentThread]);
    });

    // 在它前面的任務(wù)執(zhí)行結(jié)束后它才執(zhí)行,在它后面的任務(wù)等它執(zhí)行完成后才會(huì)執(zhí)行
    dispatch_barrier_async(queue, ^{
        NSLog(@"----barrier-----%@", [NSThread currentThread]);
    });

    dispatch_async(queue, ^{
        NSLog(@"----3-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"----4-----%@", [NSThread currentThread]);
    });
}

dispatch_group

  • 必須是并行隊(duì)列才起作用
  • 需求描述
    • 現(xiàn)有三個(gè)任務(wù):任務(wù)A、任務(wù)B、任務(wù)C
    • 任務(wù)C需要等到任務(wù)A和任務(wù)B都完成后才執(zhí)行
    • 任務(wù)A和任務(wù)B執(zhí)行沒(méi)有先后順序
  • 使用dispatch_group可以實(shí)現(xiàn)上面的需求
  • 創(chuàng)建dispatch_group_t
// 創(chuàng)建隊(duì)列組
dispatch_group_t group =  dispatch_group_create();
  • 添加任務(wù)分兩種情況
    • 自己可以控制并創(chuàng)建隊(duì)列,使用dispatch_group_async
    // 省去創(chuàng)建group、queue代碼......
    dispatch_group_async(group, queue, ^{
        // 添加任務(wù)A到group
    });
    
    dispatch_group_async(group, queue, ^{
        // 添加任務(wù)B到group
    });
    
    • 無(wú)法控制隊(duì)列,即使用的隊(duì)列不是你創(chuàng)建的(如:AFNetworking異步添加任務(wù)),此時(shí)可以使用dispatch_group_enter,dispatch_group_leave控制任務(wù)的執(zhí)行順序
    // 使用dispatch_group_enter,dispatch_group_leave可以方便的將一系列網(wǎng)絡(luò)請(qǐng)求打包起來(lái)
    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
    
    // 添加任務(wù)A到group
    // ---打標(biāo)記---
    dispatch_group_enter(group);
    [manager GET:@"http://www.baidu.com" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
      // do something
    
      // ---刪除標(biāo)記---
      dispatch_group_leave(group);
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
      // do something
    
      // ---刪除標(biāo)記---
      dispatch_group_leave(group);
    }];
    
    // 添加任務(wù)B到group類似上面的操作
    
  • 添加結(jié)束任務(wù)也分為兩種情況
    • dispatch_group_notify(推薦):不會(huì)阻塞當(dāng)前線程,馬上返回
    dispatch_group_notify(group, dispatch_get_main_queue(), ^
    {
        // do something
    });
    
    • dispatch_group_wait(不推薦):阻塞當(dāng)前線程,直到dispatch group中的所有任務(wù)完成才會(huì)返回
    // 第二個(gè)參數(shù)是超時(shí)時(shí)間
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    
  • 完整示例
// 創(chuàng)建隊(duì)列組
dispatch_group_t group =  dispatch_group_create();

// 獲取全局并發(fā)隊(duì)列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

// 添加任務(wù)A到group
dispatch_group_async(group, queue, ^{
    // 添加任務(wù)A到group
});

// 添加任務(wù)B到group
dispatch_group_async(group, queue, ^{
    // 添加任務(wù)B到group
});

// 當(dāng)任務(wù)A和任務(wù)B都執(zhí)行完后到此來(lái)執(zhí)行任務(wù)C
dispatch_group_notify(group, queue, ^{
    // 如果這里還有基于上面兩個(gè)任務(wù)的結(jié)果繼續(xù)執(zhí)行一些代碼,建議還是放到子線程中,等代碼執(zhí)行完畢后在回到主線程

    // 回到主線程
    dispatch_async(group, dispatch_get_main_queue(), ^{
        // 執(zhí)行相關(guān)UI顯示代碼...
    });
});

dispatch_set_context與dispatch_set_finalizer_f的配合使用

  • 函數(shù)作用:為隊(duì)列設(shè)置任意類型的數(shù)據(jù),并在合適的時(shí)候取出來(lái)用
  • 函數(shù)定義
// 設(shè)置context
void dispatch_set_context(dispatch_object_t object, void *context);

// 獲取context
void* dispatch_get_context(dispatch_object_t object);
  • 參數(shù)介紹
    • 第一個(gè)參數(shù)object:一般指通過(guò)dispatch_queue_create創(chuàng)建的隊(duì)列
    • dispatch_set_context函數(shù)完成了將context綁定到指定的GCD隊(duì)列上
    • dispatch_get_context函數(shù)完成了從指定的GCD隊(duì)列獲取對(duì)應(yīng)的context
    • context是一個(gè)void類型指針,學(xué)過(guò)C語(yǔ)言的朋友應(yīng)該都知道,void類型指針可以指向任意類型,context在這里可以是任意類型的指針
  • 補(bǔ)充:Foundation對(duì)象Core Foundation對(duì)象間的轉(zhuǎn)換,俗稱橋接,請(qǐng)查看這篇文章
  • 完整示例
@interface Data : NSObject

@property(assign, nonatomic) int number;

@end

@implementation Data

// 便于觀察對(duì)象何時(shí)被釋放
- (void)dealloc 
{
    NSLog(@"Data dealloc...");
}

@end

-----------------------------------------------------------------------------------------

// 定義隊(duì)列的finalizer函數(shù),用于釋放context內(nèi)存
void cleanStaff(void *context) {
    // 這里用__bridge轉(zhuǎn)換,不改變內(nèi)存管理權(quán)
    Data *data = (__bridge Data *)(context);
    NSLog(@"In clean, context number: %d", data.number);

    // 釋放context的內(nèi)存!
    CFRelease(context);
}

- (void)testBody 
{
    // 創(chuàng)建隊(duì)列
    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_CONCURRENT);

    // 創(chuàng)建Data類型context數(shù)據(jù)并初始化
    Data *myData = [Data new];
    myData.number = 10;

    // 綁定context
    // 這里用__bridge_retained將OC對(duì)象轉(zhuǎn)換為C對(duì)象,將context的內(nèi)存管理權(quán)從ARC移除,交由我們自己手動(dòng)釋放!
    dispatch_set_context(queue, (__bridge_retained void *)(myData));

    // 設(shè)置finalizer函數(shù),用于在隊(duì)列執(zhí)行完成后釋放對(duì)應(yīng)context內(nèi)存
    dispatch_set_finalizer_f(queue, cleanStaff);

    dispatch_async(queue, ^
   {
        // 獲取隊(duì)列的context數(shù)據(jù)
        // 這里用__bridge將C對(duì)象裝換為OC對(duì)象轉(zhuǎn)換,并沒(méi)有改變內(nèi)存管理權(quán)
        Data *data = (__bridge Data *)(dispatch_get_context(queue));
        // 打印
        NSLog(@"1: context number: %d", data.number);
        // 修改context保存的數(shù)據(jù)
        data.number = 20;
    });
}

參考文章

最后編輯于
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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