【iOS】簡(jiǎn)述下OC block的實(shí)現(xiàn)

block 實(shí)際上是OC 對(duì)閉包c(diǎn)losure的實(shí)現(xiàn)

block的數(shù)據(jù)結(jié)構(gòu)

先來(lái)看下block的結(jié)構(gòu)示意圖:

block的數(shù)據(jù)結(jié)構(gòu)

各組成部分含義:

  1. isa:該對(duì)象是什么
  2. flags:block附加信息
  3. reserve:保留變量
  4. invoke:函數(shù)實(shí)現(xiàn)指針
  5. descriptor:block 描述符,主要是block的一些附加信息
  6. variables:capture過(guò)來(lái)的變量

這樣來(lái)看的話,block就是函數(shù) + 數(shù)據(jù),即持有著一些數(shù)據(jù)的函數(shù),編譯后生成相應(yīng)的結(jié)構(gòu)體和函數(shù)指針,結(jié)構(gòu)體保存著數(shù)據(jù),

block的三種類型

在OC中block的類型分為三類:

  1. _NSConcreteGlobalBlock 全局的靜態(tài) block,不會(huì)訪問(wèn)任何外部變量。
  2. _NSConcreteStackBlock 保存在棧中的 block,當(dāng)函數(shù)返回時(shí)會(huì)被銷毀。
  3. _NSConcreteMallocBlock 保存在堆中的 block,當(dāng)引用計(jì)數(shù)為 0 時(shí)會(huì)被銷毀。

以下說(shuō)明幾點(diǎn)需要注意的:

  1. _NSConcreteGlobalBlock 是全局靜態(tài)block,結(jié)構(gòu)體存儲(chǔ)在數(shù)據(jù)區(qū)。
  2. 常見(jiàn)的是有捕獲外部變量的_NSConcreteStackBlock,需要注意的是如果這種類型的block 定義在函數(shù)內(nèi)部,當(dāng)函數(shù)執(zhí)行完畢,退棧的時(shí)候會(huì)將該block結(jié)構(gòu)體所占的內(nèi)存空間釋放掉,這樣再引用的話會(huì)報(bào)錯(cuò)。
  3. _NSConcreteMallocBlock 通常不會(huì)在源碼中直接出現(xiàn),OC ARC下會(huì)對(duì)_NSConcreteStackBlock 進(jìn)行優(yōu)化,將其copy到堆上,轉(zhuǎn)換成_NSConcreteMallocBlock,所以無(wú)特殊處理,OC中將只會(huì)有1,3兩種類型block
  4. _NSConcreteStackBlock捕獲的局部變量,如不加_block修飾符,將會(huì)把變量copy一份到其結(jié)構(gòu)體中,所以才會(huì)在內(nèi)部修改不影響外部變量,加_block修飾之后,結(jié)構(gòu)體中會(huì)添加一個(gè)__Block_byref_i_0 的結(jié)構(gòu)體,且復(fù)制的是變量地址,達(dá)到可以修改外部變量的效果。關(guān)于這部分詳細(xì):這里

block的內(nèi)存測(cè)試

下面簡(jiǎn)要的看幾個(gè)例子,分析下其是否生效,即生效的前提,每個(gè)例子的答案選項(xiàng)都有4個(gè):

  1. always works
  2. only works with ARC
  3. only works without ARC
  4. never works
Example A:
void exampleA() {
  char a = 'A';
  ^{
    printf("%cn", a);
  }();
}
Example B:
void exampleB_addBlockToArray(NSMutableArray *array) {
  char b = 'B';
  [array addObject:^{
    printf("%cn", b);
  }];
}

void exampleB() {
  NSMutableArray *array = [NSMutableArray array];
  exampleB_addBlockToArray(array);
  void (^block)() = [array objectAtIndex:0];
  block();
}
Example C:
void exampleC_addBlockToArray(NSMutableArray *array) {
  [array addObject:^{
    printf("Cn");
  }];
}

void exampleC() {
  NSMutableArray *array = [NSMutableArray array];
  exampleC_addBlockToArray(array);
  void (^block)() = [array objectAtIndex:0];
  block();
}
Example D:
typedef void (^dBlock)();

dBlock exampleD_getBlock() {
  char d = 'D';
  return ^{
    printf("%cn", d);
  };
}

void exampleD() {
  exampleD_getBlock()();
}
Example E:
typedef void (^eBlock)();

eBlock exampleE_getBlock() {
  char e = 'E';
  void (^block)() = ^{
    printf("%cn", e);
  };
  return block;
}

void exampleE() {
  eBlock block = exampleE_getBlock();
  block();
}
  • A:always works,此block類型是_NSConcreteStackBlock,但block調(diào)用在函數(shù)體內(nèi),函數(shù)釋放前已經(jīng)執(zhí)行完畢,所以無(wú)論在棧上還是堆上都可以正常執(zhí)行。
  • B:only works with ARC,非ARC的話,block內(nèi)存空間在函數(shù)exampleB_addBlockToArray的棧上,此函數(shù)執(zhí)行完畢,退棧時(shí)候內(nèi)存空間清空,引用報(bào)錯(cuò)。ARC下會(huì)被轉(zhuǎn)換成_NSConcreteMallocBlock,copy到堆上所以生效。
  • C:always works,此block類型是_NSConcreteGlobalBlock,存儲(chǔ)在數(shù)據(jù)區(qū),所以一直生效。
  • D:only works with ARC,同B,但編譯器無(wú)法編譯,會(huì)報(bào)錯(cuò)。
  • E:only works with ARC,同D,但編譯器不會(huì)報(bào)錯(cuò),更需注意。
最后編輯于
?著作權(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)容

  • 《Objective-C高級(jí)編程》這本書(shū)就講了三個(gè)東西:自動(dòng)引用計(jì)數(shù)、block、GCD,偏向于從原理上對(duì)這些內(nèi)容...
    WeiHing閱讀 10,085評(píng)論 10 69
  • 前言 Blocks是C語(yǔ)言的擴(kuò)充功能,而Apple 在OS X Snow Leopard 和 iOS 4中引入了這...
    小人不才閱讀 3,851評(píng)論 0 23
  • 一、Objective-C發(fā)展史 Objective-C從1983年誕生,已經(jīng)走過(guò)了30多年的歷程。隨著時(shí)間的推移...
    沒(méi)事蹦蹦閱讀 5,995評(píng)論 12 34
  • 摘要 Blocks是C語(yǔ)言的擴(kuò)充功能, iOS 4中引入了這個(gè)新功能“Blocks”,那么block到底是什么東西...
    CholMay閱讀 1,303評(píng)論 2 10
  • Block基礎(chǔ)回顧 1.什么是Block? 帶有局部變量的匿名函數(shù)(名字不重要,知道怎么用就行),差不多就與C語(yǔ)言...
    Bugfix閱讀 6,901評(píng)論 5 61

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