iOS - block - 捕獲基本類型

[toc]

參考

block - 捕獲基本類型

OC代碼

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSInteger val = 10;
        NSLog(@"1_val = %ld - %p", val, &val);

        void (^block)(void) = ^{
            NSLog(@"2_val = %ld - %p", val, &val);
        };
        NSLog(@"3_val = %ld - %p", val, &val);

        block();
        NSLog(@"4_val = %ld - %p", val, &val);
    }
    return 0;
}

MRC 輸出: 
1_val = 10 - 0x7ffeefbff408
3_val = 10 - 0x7ffeefbff408
2_val = 10 - 0x7ffeefbff3f8 // 包內(nèi): 新的棧地址
4_val = 10 - 0x7ffeefbff408

ARC 輸出: 
1_val = 10 - 0x7ffeefbff408
3_val = 10 - 0x7ffeefbff408
2_val = 10 - 0x103a34b30 // 包內(nèi): 堆地址
4_val = 10 - 0x7ffeefbff408
結(jié)論★:

block 訪問(wèn)未被 __block 修飾的非靜態(tài)局部變量:

  • block 包外, 無(wú)論MRC/ARC, 在block定義前后, 局部變量的地址未改變, 始終在棧上梁棠。

    • 這種情況下, block并不會(huì)改變包外變量的地址。
  • block 包內(nèi), 局部變量的瞬時(shí)值被捕獲為block結(jié)構(gòu)體的成員, 生成一個(gè)全新的變量, 擁有新的地址竖共。

    • MRC下, block仍然在棧上, 所以局部變量也在棧上;

    • ARC下, block因被強(qiáng)指針引用, 會(huì)被copy到堆, 所以局部變量也隨block拷貝到了堆;

☆ 變量被copy到堆, 并不是__block的作用竹伸。

注意:

若未使用 __block, block中做如下修改 val = 2; , 編譯會(huì)報(bào)錯(cuò) "Variable is not assignable (missing __block type specifier)” , 即, 不能修改指針指向旱易。

如何證明 "block內(nèi)部” 打印的是堆地址?

把三個(gè)16進(jìn)制的內(nèi)存地址轉(zhuǎn)成10進(jìn)制就是:

定義前:6171559672 6171041512

包內(nèi)部:5732708296 6174180216

定義后:5732708296

中間相差 438851376 個(gè)字節(jié), 也就是 418.5M 的空間, 因?yàn)槎训刂芬∮跅5刂? 又因?yàn)閕OS中一個(gè)進(jìn)程的棧區(qū)內(nèi)存只有1M, Mac也只有8M, 顯然a已經(jīng)是在堆區(qū)了岖瑰。


C++代碼

MRC/ARC下, 編譯的C++代碼一致:

int main(int argc, const char * argv[]) {
    { __AtAutoreleasePool __autoreleasepool; 
        NSInteger val = 10; // 局部變量
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_p5_mp3284bs2xb073r91w__n99r0000gn_T_main_d3fa5d_mi_0, val, &val);

        void (*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, val)); // 注意第3個(gè)參數(shù) val
     
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_p5_mp3284bs2xb073r91w__n99r0000gn_T_main_d3fa5d_mi_2, val, &val);

        ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_p5_mp3284bs2xb073r91w__n99r0000gn_T_main_d3fa5d_mi_3, val, &val);
    }
    return 0;
}

// block 的結(jié)構(gòu)體
struct __main_block_impl_0 {
    struct __block_impl impl;
    struct __main_block_desc_0* Desc;
    NSInteger val; // 捕獲到的局部變量

    // 結(jié)構(gòu)體構(gòu)造函數(shù)
    __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, NSInteger _val, int flags=0) : val(_val) { 
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
    }
};

// __main_block_impl_0 初始化的第1個(gè)參數(shù), 作為函數(shù)指針傳遞
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
    NSInteger val = __cself->val; // bound by copy
    NSLog((NSString *)&__NSConstantStringImpl__var_folders_p5_mp3284bs2xb073r91w__n99r0000gn_T_main_d3fa5d_mi_1, val, &val);
}

// __main_block_impl_0 初始化的第2個(gè)參數(shù)
// 注意, 未使用 __block修飾基本數(shù)據(jù)類型的局部變量, desc結(jié)構(gòu)體中沒(méi)有 copy 和 dispoose 函數(shù)
static struct __main_block_desc_0 {
    size_t reserved; 
    size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0) };

block 被轉(zhuǎn)換成了一個(gè) __main_block_impl_0 的結(jié)構(gòu)體實(shí)例, 其中, 結(jié)構(gòu)體 __main_block_impl_0 的成員包含了捕獲到的局部變量val狮杨。

在結(jié)構(gòu)體 __main_block_impl_0 的構(gòu)造方法中, 局部變量val作為第3個(gè)入?yún)? 被捕獲半沽。

執(zhí)行block時(shí), 通過(guò) block 找到 __main_block_func_0 , 并把當(dāng)前block作為參數(shù)傳遞到 __main_block_func_0 函數(shù)中身诺。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市抄囚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌橄务,老刑警劉巖幔托,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡重挑,警方通過(guò)查閱死者的電腦和手機(jī)嗓化,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)谬哀,“玉大人刺覆,你說(shuō)我怎么就攤上這事∈芳澹” “怎么了谦屑?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)篇梭。 經(jīng)常有香客問(wèn)我氢橙,道長(zhǎng),這世上最難降的妖魔是什么恬偷? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任悍手,我火速辦了婚禮,結(jié)果婚禮上袍患,老公的妹妹穿的比我還像新娘坦康。我一直安慰自己,他們只是感情好诡延,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布滞欠。 她就那樣靜靜地躺著,像睡著了一般孕暇。 火紅的嫁衣襯著肌膚如雪仑撞。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,749評(píng)論 1 289
  • 那天妖滔,我揣著相機(jī)與錄音隧哮,去河邊找鬼。 笑死座舍,一個(gè)胖子當(dāng)著我的面吹牛沮翔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播曲秉,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼采蚀,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了承二?” 一聲冷哼從身側(cè)響起榆鼠,我...
    開(kāi)封第一講書(shū)人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎亥鸠,沒(méi)想到半個(gè)月后妆够,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體识啦,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年神妹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了颓哮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鸵荠,死狀恐怖冕茅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蛹找,我是刑警寧澤姨伤,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站熄赡,受9級(jí)特大地震影響姜挺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜彼硫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一炊豪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拧篮,春花似錦词渤、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至礁凡,卻和暖如春高氮,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背顷牌。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工剪芍, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人窟蓝。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓罪裹,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親运挫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子状共,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

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