OC block 原理總結(jié)

本文重點總結(jié) OC block 的原理,并帶上一些例子,不討論 block 的寫法和應(yīng)用。

block 的本質(zhì)總結(jié)如下:

  • block 在底層上是一個結(jié)構(gòu)體,內(nèi)部有一個isa指針萍倡,指向block所屬的類,其父類最終指向NSObject辟汰,所以可以把block看做對象
void (^ blk)(void) = ^{
  NSLog(@"hello");
};

NSLog(@"%@", [blk class]);  // __NSGlobalBlock__
NSLog(@"%@", [[blk class] superclass]);  // __NSGlobalBlock
NSLog(@"%@", [[[blk class] superclass] superclass]);  // NSBlock
NSLog(@"%@", [[[[blk class] superclass] superclass] superclass]);  // NSObject
  • block 有三種類型:_NSConcreteGlobalBlock(全局block), _NSConcreteStackBlock (棧block), _NSConcreteMallocBlock (堆block)列敲,分別儲存在data區(qū)棧區(qū)帖汞,堆區(qū)戴而,他們的類型由創(chuàng)建方式以及創(chuàng)建時候捕獲的變量類型決定。
  • 不使用外部變量的block是全局block翩蘸,使用外部變量并且未進行copy操作的block是棧block所意,對棧block進行copy操作,就是堆block催首,而對全局block進行copy扶踊,仍是全局block。
// 不使用外部變量
NSLog(@"%@", [^{
  NSLog(@"globalBlock");
} class]);  // __NSGlobalBlock__

// 使用外部變量并且未進行copy
NSInteger num = 10;
NSLog(@"%@", [^{
  NSLog(@"stackBlock:%zd", num);
} class]);  // __NSStackBlock__

// 對全局block進行copy
void (^ globalBlock)(void) = [^{
  NSLog(@"globalBlock");
} copy];
NSLog(@"%@", [globalBlock class]);  //  __NSGlobalBlock__

// 對棧block進行copy操作
void (^ mallocBlock)(void) = [^{
  NSLog(@"stackBlock:%zd", num);
} copy];
NSLog(@"%@", [mallocBlock class]);  //  __NSMallocBlock__
  • 為了解決block所在變量域結(jié)束后block仍然可用的問題郎任,需要把棧block復(fù)制到堆上秧耗。

  • ARC時,在四種情況下棧block會自動復(fù)制到堆上

    • 手動copy
    • block作為函數(shù)返回值
    • block賦值給__strong修飾的變量或Block類型成員變量時
    • 向Cocoa框架含有usingBlock的方法或者GCD的API傳遞Block參數(shù)時 )
  • MRC只有手動copy涝滴,才會復(fù)制到堆上

  • block可以捕獲他周圍的變量绣版,分為:全局變量胶台、自動變量(函數(shù)棧上的默認變量)歼疮、靜態(tài)變量(函數(shù)棧上加static關(guān)鍵字的變量)、__block變量(函數(shù)棧上加__block關(guān)鍵字的變量)

  • 全局變量诈唬,因為作用域范圍廣韩脏,所以可以在block內(nèi)改變它們的值。

  • block捕獲的自動變量又分為基本數(shù)據(jù)類型變量(如int,double)和指針型變量(如:對象)铸磅,捕獲的是自動變量的值赡矢,不能在block內(nèi)部改變自動變量的值。

  • block捕獲的靜態(tài)變量是變量的地址阅仔。通過使用靜態(tài)變量的指針對其進行訪問吹散,可以在block內(nèi)改變值。

  • block變量在底層是一個結(jié)構(gòu)體八酒,也有isa指針空民,可以看成一個對象。

  • block捕獲__block變量,捕獲的是對應(yīng)結(jié)構(gòu)體的變量的地址界轩,可以在block內(nèi)直接改變值画饥。

  • 當block復(fù)制到堆上,block使用到的__block變量也會被復(fù)制到堆上并被block持有浊猾。

  • __block變量結(jié)構(gòu)體內(nèi)有__forwarding指針抖甘,棧上的__forwarding指針會指向堆上的__forwarding變量,而堆上的__forwarding指針指向其自身葫慎,所以如果對__block的修改(棧上的還是堆上的)衔彻,實際上永遠只會修改堆上的__block變量。

  • 當block復(fù)制到堆上后偷办,其對獲取的變量的關(guān)系如下:->表示持有

    • 自動變量:堆Block -> 變量的值 (不能改變)
    • 靜態(tài)變量:堆Block -> 變量的地址(可以改變變量)
    • __block 普通基本數(shù)據(jù)類型變量:堆Block -> 堆__block變量 (此時變量的值被復(fù)制到了堆了米奸,可以改變變量的值)
    • __block __strong 對象類型變量: 堆Block -> 堆__block變量 -> 對象 (對象本身就是在堆上,可以改變對象的值)
  • 堆上的block如果捕獲了強引用對象爽篷,那個對象又引用了block悴晰,會照成循環(huán)引用

  • 可以用__weak修飾應(yīng)用block的對象,避免循環(huán)引用

  • 假設(shè) self 引用了block逐工,用__weak修飾(__weak typeof(self) weakSelf = sellf;)避免循環(huán)引用铡溪,如果block執(zhí)行完成之前,self被釋放了泪喊,weakSelf也會變?yōu)?nil棕硫,可能引起奔潰,我們在block中使用__strong修飾weakSelf保證任何情況下袒啼,self在超出作用域后仍能夠使用哈扮,防止self的提前釋放: __strong typeof(weakSelf) strongSelf = weakSelf

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蚓再,隨后出現(xiàn)的幾起案子滑肉,更是在濱河造成了極大的恐慌,老刑警劉巖摘仅,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件靶庙,死亡現(xiàn)場離奇詭異,居然都是意外死亡娃属,警方通過查閱死者的電腦和手機六荒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來矾端,“玉大人掏击,你說我怎么就攤上這事≈让” “怎么了砚亭?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我钠惩,道長柒凉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任篓跛,我火速辦了婚禮膝捞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘愧沟。我一直安慰自己蔬咬,他們只是感情好,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布沐寺。 她就那樣靜靜地躺著林艘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪混坞。 梳的紋絲不亂的頭發(fā)上狐援,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天,我揣著相機與錄音究孕,去河邊找鬼啥酱。 笑死,一個胖子當著我的面吹牛厨诸,可吹牛的內(nèi)容都是我干的镶殷。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼微酬,長吁一口氣:“原來是場噩夢啊……” “哼绘趋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起颗管,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤陷遮,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后忙上,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拷呆,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡闲坎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年疫粥,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片腰懂。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡梗逮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出绣溜,到底是詐尸還是另有隱情慷彤,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站底哗,受9級特大地震影響岁诉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜跋选,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一涕癣、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧前标,春花似錦坠韩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至俭尖,卻和暖如春氢惋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背稽犁。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工明肮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人缭付。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓柿估,卻偏偏與公主長得像,于是被迫代替她去往敵國和親陷猫。 傳聞我的和親對象是個殘疾皇子秫舌,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359