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

block 實際上是OC 對閉包closure的實現(xiàn)

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

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

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

各組成部分含義:

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

這樣來看的話碉渡,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光绕,不會訪問任何外部變量。
  2. _NSConcreteStackBlock 保存在棧中的 block畜份,當(dāng)函數(shù)返回時會被銷毀诞帐。
  3. _NSConcreteMallocBlock 保存在堆中的 block,當(dāng)引用計數(shù)為 0 時會被銷毀爆雹。

以下說明幾點需要注意的:

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

block的內(nèi)存測試

下面簡要的看幾個例子李皇,分析下其是否生效钦奋,即生效的前提,每個例子的答案選項都有4個:

  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í)行完畢圃阳,所以無論在棧上還是堆上都可以正常執(zhí)行。
  • B:only works with ARC璧帝,非ARC的話捍岳,block內(nèi)存空間在函數(shù)exampleB_addBlockToArray的棧上,此函數(shù)執(zhí)行完畢睬隶,退棧時候內(nèi)存空間清空锣夹,引用報錯。ARC下會被轉(zhuǎn)換成_NSConcreteMallocBlock苏潜,copy到堆上所以生效银萍。
  • C:always works,此block類型是_NSConcreteGlobalBlock恤左,存儲在數(shù)據(jù)區(qū)贴唇,所以一直生效搀绣。
  • D:only works with ARC,同B戳气,但編譯器無法編譯链患,會報錯。
  • E:only works with ARC瓶您,同D麻捻,但編譯器不會報錯,更需注意呀袱。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末贸毕,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子压鉴,更是在濱河造成了極大的恐慌崖咨,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件油吭,死亡現(xiàn)場離奇詭異击蹲,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)婉宰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進(jìn)店門歌豺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人心包,你說我怎么就攤上這事类咧。” “怎么了蟹腾?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵痕惋,是天一觀的道長。 經(jīng)常有香客問我娃殖,道長值戳,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任炉爆,我火速辦了婚禮堕虹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘芬首。我一直安慰自己赴捞,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布郁稍。 她就那樣靜靜地躺著赦政,像睡著了一般。 火紅的嫁衣襯著肌膚如雪耀怜。 梳的紋絲不亂的頭發(fā)上昼钻,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天掸屡,我揣著相機(jī)與錄音,去河邊找鬼然评。 笑死仅财,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的碗淌。 我是一名探鬼主播盏求,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼亿眠!你這毒婦竟也來了碎罚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤纳像,失蹤者是張志新(化名)和其女友劉穎荆烈,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體竟趾,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡憔购,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了岔帽。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片玫鸟。...
    茶點故事閱讀 38,643評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖犀勒,靈堂內(nèi)的尸體忽然破棺而出屎飘,到底是詐尸還是另有隱情,我是刑警寧澤贾费,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布钦购,位于F島的核電站,受9級特大地震影響褂萧,放射性物質(zhì)發(fā)生泄漏押桃。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一箱玷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧陌宿,春花似錦锡足、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至爽蝴,卻和暖如春沐批,著一層夾襖步出監(jiān)牢的瞬間纫骑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工九孩, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留先馆,地道東北人。 一個月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓躺彬,卻偏偏與公主長得像煤墙,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子宪拥,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,509評論 2 348

推薦閱讀更多精彩內(nèi)容

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