(二)Block之存儲域 NSConcreteStackBlock芙粱,NSConcreteGlobalBlock祭玉,NSConcreteMallocBlock

相關文章


我們已經(jīng)知道脱货,Block將被轉(zhuǎn)換為Block的結(jié)構(gòu)體的自動變量, 即棧上生成的結(jié)構(gòu)體實例律姨。而且當Block被當做OC對象來看時振峻,Block的isa指針為_NSConcreteStackBlock

導讀

本文以下內(nèi)容我們將探究包括_NSConcreteStackBlock的與之相似的幾個類:

  • _NSConcreteStackBlock
  • _NSConcreteGlobalBlock
  • _NSConcreteMallocBlock

_NSConcreteStackBlock中包stack關鍵字,我們可以推測它設置在棧上(編譯器分配內(nèi)存)
_NSConcreteGlobalBlock中包Global關鍵字择份,我們可以推測它設置在數(shù)據(jù)區(qū)域
_NSConcreteMallocBlock中包Malloc關鍵字扣孟,我們可以推測它設置在堆上(由程序員分配內(nèi)存)

那么在分配內(nèi)存上對應區(qū)域:

程序內(nèi)存分配.png
設置對象的存儲于
_NSConcreteStackBlock
_NSConcreteGlobalBlock 數(shù)據(jù)區(qū)
_NSConcreteMallocBlock

_NSConcreteStackBlock

int i = 0;
void (^blk)() = ^() {
    printf("%d", i);
};
blk();

局部定義的Block 經(jīng)過代碼轉(zhuǎn)換后

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
    impl.isa = &_NSConcreteStackBlock; //設置在棧區(qū)的Block
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

大多數(shù)時候,clang轉(zhuǎn)換的源代碼通常是_NSConcreteStackBlock對象

_NSConcreteGlobalBlock

void (^blk) () = ^{
    printf("Block");
};
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        blk();
    }
    return 0;
}

全局定義的Block經(jīng)過代碼轉(zhuǎn)換后

struct __blk_block_impl_0 {
  struct __block_impl impl;
  struct __blk_block_desc_0* Desc;
  __blk_block_impl_0(void *fp, struct __blk_block_desc_0 *desc, int flags=0) {
    impl.isa = &_NSConcreteGlobalBlock; //設置在數(shù)據(jù)區(qū)的Block
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

當以下兩種情況時荣赶,Block被轉(zhuǎn)換為_NSConcreteGlobalBlock

  • 全局變量有Block語法的時候
    全局變量的地方不能使用自動變量凤价,不存在對自動變量進行捕獲的情況,所以Block不依賴執(zhí)行時候的狀態(tài)拔创,這時候Block設置為_NSConcreteGlobalBlock
  • Block語法不使用截獲的自動變量時候
int(^blk)(int count) = ^(int count) {
     return count;
};

示例代碼如上利诺,Block并不需要捕獲自動變量,也可以將Block設置在數(shù)據(jù)區(qū)域

_NSConcreteMallocBlock

對于以下代碼

typedef int (^Block)(int num);

Block foo(){
    int i = 0;
    return ^{printf("blk:%d", i);};
}

將如上代碼轉(zhuǎn)換為匯編輸出(如何獲取匯編代碼輸出請看 iOS 獲取匯編輸出方法 以下采用整理過后的偽代碼形式)

Block foo(){
    int i = 0;
    Block tmp = &__foo_block_impl_0(
                          &__foo_block_func_0, 
                         &__foo_block_desc_0_DATA,
                          i));
    tmp = objc_retainBlock(tmp);
    return objc_autoreleaseReturnValue(tmp);
}

如下為objc_retainBlock的源碼

id objc_retainBlock(id x) {
    return (id)_Block_copy(x);
}

很顯然調(diào)用了objc_retainBlock就等于調(diào)用了_Block_copy, 作用是將Block拷貝至堆伏蚊。

那么立轧,當以下情況時,Block被拷貝至堆躏吊,那么Block也將配置為_NSConcreteMallocBlock

  • Block作為返回值氛改,超出了變量作用域

補充

Block作為返回值時,編譯器會自動將變量拷貝至堆比伏,有時候編譯器無法判斷胜卤,需要手動調(diào)用copy方法,將Block拷貝至堆


typedef void (^Block)();

id foo(){
    int i = 0;
    return [[NSArray alloc] initWithObjects:
            ^{printf("blk:%d", i);},
            nil];
}

NSArray *arr = foo();
Block blk = (Block)[arr firstObject];
blk();//此處執(zhí)行報錯

該段代碼執(zhí)行將會報錯赁项,因為foo()執(zhí)行結(jié)束后葛躏,棧上的Block就被釋放了,所以需要手動copy 下Block

id foo(){
    int i = 0;
    return [[NSArray alloc] initWithObjects:
           [^{printf("blk:%d", i);} copy],//手動copy block到堆
            nil];
}

最后附上各類Block Copy后執(zhí)行動作

設置對象的存儲于 Copy動作執(zhí)行后
_NSConcreteStackBlock 棧復制到堆
_NSConcreteGlobalBlock 數(shù)據(jù)區(qū) 不做變化
_NSConcreteMallocBlock 引用計數(shù)增加
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末悠菜,一起剝皮案震驚了整個濱河市舰攒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌悔醋,老刑警劉巖摩窃,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡猾愿,警方通過查閱死者的電腦和手機鹦聪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蒂秘,“玉大人泽本,你說我怎么就攤上這事∫錾” “怎么了规丽?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長段化。 經(jīng)常有香客問我嘁捷,道長,這世上最難降的妖魔是什么显熏? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任雄嚣,我火速辦了婚禮,結(jié)果婚禮上喘蟆,老公的妹妹穿的比我還像新娘缓升。我一直安慰自己,他們只是感情好蕴轨,可當我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布港谊。 她就那樣靜靜地躺著,像睡著了一般橙弱。 火紅的嫁衣襯著肌膚如雪歧寺。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天棘脐,我揣著相機與錄音斜筐,去河邊找鬼。 笑死蛀缝,一個胖子當著我的面吹牛顷链,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播屈梁,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼嗤练,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了在讶?” 一聲冷哼從身側(cè)響起煞抬,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎构哺,沒想到半個月后此疹,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年蝗碎,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片旗扑。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡蹦骑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出臀防,到底是詐尸還是另有隱情眠菇,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布袱衷,位于F島的核電站捎废,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏致燥。R本人自食惡果不足惜登疗,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望嫌蚤。 院中可真熱鬧辐益,春花似錦、人聲如沸脱吱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽箱蝠。三九已至续捂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間宦搬,已是汗流浹背牙瓢。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留床三,地道東北人一罩。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像撇簿,于是被迫代替她去往敵國和親聂渊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,871評論 2 354

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