block中加__block深刻含義

Block不允許修改外部變量的值,這里所說(shuō)的外部變量的值,指的是棧中指針的內(nèi)存地址。__block所起到的作用就是只要觀(guān)察到該變量被 block 所持有,就將“外部變量”在棧中的內(nèi)存地址放到了堆中。進(jìn)而在block內(nèi)部也可以修改外部變量的值。---這是 微博@唐巧_boy的《iOS開(kāi)發(fā)進(jìn)階》中的第11.2.3章節(jié)中的描述。

簡(jiǎn)單數(shù)據(jù)類(lèi)型局部變量

加上__block情況
  1. 在這里a是局部變量,所以是放在棧當(dāng)中的。block相當(dāng)于另一個(gè)內(nèi)部函數(shù),要在另一個(gè)作用域中改變棧中指針的內(nèi)存地址是不行的。此時(shí),如果block想要在內(nèi)部進(jìn)行操作就要將a變量拷貝到堆中,程序才能去改變。
  2. 在block中再次打印a地址,可以發(fā)現(xiàn)地址不一樣了。這就是__block的作用,它將棧中的變量a進(jìn)行copy放到堆上。(此時(shí)輸出的是堆地址)
  3. 0x7開(kāi)頭的是在棧上的地址。0x1開(kāi)頭的為堆上地址。
  4. 在調(diào)用block后,a變量就已經(jīng)是新的內(nèi)存地址,也不再是棧上。
  5. 這里如果不加__block,a = 3就是修改a指針的內(nèi)存地址。這樣是不行的。

不可變對(duì)象局部變量

NSString對(duì)象
  1. NSString為不可變字符串,初始化后不能修改內(nèi)容(這里內(nèi)容指的是堆上開(kāi)辟的空間內(nèi)容)。不加__block的情況下,string指針引用永遠(yuǎn)為初始化時(shí)的內(nèi)容地址(也就是永遠(yuǎn)指向@“dddd”)。
  2. 加上__block后,在block內(nèi)部會(huì)將string從棧copy到堆上。這樣我們就可以操作string的指針內(nèi)存地址,進(jìn)行修改。也就是可以 string = @“fffff”的操作。
  3. 可以看出block以后,string的所有都copy到堆中。(特別說(shuō)明:一個(gè)對(duì)象的生成,會(huì)在棧中開(kāi)辟指針地址,指針地址中存放一個(gè)堆地址,這個(gè)地址就是真正存放對(duì)象內(nèi)容的區(qū)域。也就是說(shuō)對(duì)象都是放在堆上的。)

可變對(duì)象局部變量

<p>(1)添加__block情況</p>

<pre><code>
` int b = 1;
__block NSMutableString *a = [NSMutableString stringWithString:@"Tom"];
NSLog(@"開(kāi)始%@",a);
NSLog(@"b的地址為棧地址開(kāi)頭%p",&b);
NSLog(@"\n 定以前:------------------------------------\n
a指向的堆中地址:%p;a在棧中的指針地址:%p", a, &a); //a在棧區(qū)
void (^foo)(void) = ^{

        a.string = @"Jerry";
        NSLog(@"\n block內(nèi)部:------------------------------------\n\
              a指向的堆中地址:%p;a在棧中的指針地址:%p", a, &a);               //a在棧區(qū)
        a = [NSMutableString stringWithString:@"William"];
        
        NSLog(@"block內(nèi)部%@",a);
    };
    foo();
    NSLog(@"\n 定以后:------------------------------------\n\
          a指向的堆中地址:%p;a在棧中的指針地址:%p", a, &a);               //a在棧區(qū)
    
    NSLog(@"最后%@",a);`

</code>
</pre>


添加__block情況輸出結(jié)果
  1. 可以發(fā)現(xiàn)經(jīng)過(guò)block后,將a的內(nèi)容全部都copy到堆上了。
  2. a = [NSMutableString stringWithString:@"William"]; 就是更改了a指針地址內(nèi)容。

<p>(2)不添加__block情況</p>

<pre><code>
` int b = 1;
NSMutableString *a = [NSMutableString stringWithString:@"Tom"];
NSLog(@"開(kāi)始%@",a);
NSLog(@"b的地址為棧地址開(kāi)頭%p",&b);
NSLog(@"\n 定以前:------------------------------------\n
a指向的堆中地址:%p;a在棧中的指針地址:%p", a, &a); //a在棧區(qū)
void (^foo)(void) = ^{

        a.string = @"Jerry";
        NSLog(@"\n block內(nèi)部:------------------------------------\n\
              a指向的堆中地址:%p;a在棧中的指針地址:%p", a, &a);               //a在棧區(qū)
      //  a = [NSMutableString stringWithString:@"William"];
        
        NSLog(@"block內(nèi)部%@",a);
    };
    foo();
    NSLog(@"\n 定以后:------------------------------------\n\
          a指向的堆中地址:%p;a在棧中的指針地址:%p", a, &a);               //a在棧區(qū)
    
    NSLog(@"最后%@",a);`

</code>
</pre>

不添加__block情況輸出結(jié)果
  1. 可變對(duì)象可以不加__block情況下,直接修改內(nèi)容。
  2. a.string = @"Jerry" 修改的是堆上的內(nèi)容。并不是a在棧上的指針地址。
  3. 所以最后a在堆上地址和a在棧上地址并沒(méi)有改變。改變的只是a在堆上地址指向的內(nèi)容。
    參考iOS中__block 關(guān)鍵字的底層實(shí)現(xiàn)原理自己總結(jié)的內(nèi)容,如果有哪里有錯(cuò)誤還請(qǐng)大家指教。
最后編輯于
?著作權(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)容僅代表作者本人觀(guān)點(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,098評(píng)論 10 69
  • 從三月份找實(shí)習(xí)到現(xiàn)在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂(lè)視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,798評(píng)論 11 349
  • ———————————————回答好下面的足夠了---------------------------------...
    恒愛(ài)DE問(wèn)候閱讀 1,843評(píng)論 0 4
  • 多線(xiàn)程、特別是NSOperation 和 GCD 的內(nèi)部原理。運(yùn)行時(shí)機(jī)制的原理和運(yùn)用場(chǎng)景。SDWebImage的原...
    LZM輪回閱讀 2,120評(píng)論 0 12
  • *面試心聲:其實(shí)這些題本人都沒(méi)怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來(lái)就是把...
    Dove_iOS閱讀 27,618評(píng)論 30 472

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