iOS面試題:一個int變量被__block修飾與否的區(qū)別?

沒有修飾,被block捕獲,是值拷貝。
使用__block修飾,會生成一個結(jié)構(gòu)體,復(fù)制int的引用地址。達(dá)到修改數(shù)據(jù)。

1、block截獲自動變量(局部變量)值

對于 block 外的變量引用,block 默認(rèn)是將其復(fù)制到其數(shù)據(jù)結(jié)構(gòu)中來實現(xiàn)訪問的。也就是說block的自動變量截獲只針對block內(nèi)部使用的自動變量, 不使用則不截獲, 因為截獲的自動變量會存儲于block的結(jié)構(gòu)體內(nèi)部, 會導(dǎo)致block體積變大。特別要注意的是默認(rèn)情況下block只能訪問不能修改局部變量的值。

2、 __block 修飾的外部變量

對于用 __block 修飾的外部變量引用,block 是復(fù)制其引用地址來實現(xiàn)訪問的。block可以修改__block 修飾的外部變量的值。

3、Block的存儲域及copy操作

先來思考一下:Block是存儲在棧上還是堆上呢?
其實,block有三種類型:

  • 全局塊(_NSConcreteGlobalBlock)
  • 棧塊(_NSConcreteStackBlock)
  • 堆塊(_NSConcreteMallocBlock)

全局塊存在于全局內(nèi)存中, 相當(dāng)于單例.
棧塊存在于棧內(nèi)存中, 超出其作用域則馬上被銷毀
堆塊存在于堆內(nèi)存中, 是一個帶引用計數(shù)的對象, 需要自行管理其內(nèi)存
簡而言之,存儲在棧中的Block就是棧塊、存儲在堆中的就是堆塊、既不在棧中也不在堆中的塊就是全局塊。

遇到一個Block,我們怎么這個Block的存儲位置呢?

(1)Block不訪問外界變量(包括棧中和堆中的變量)

Block 既不在棧又不在堆中,在代碼段中,ARC和MRC下都是如此。此時為全局塊。

(2)Block訪問外界變量

MRC 環(huán)境下:訪問外界變量的 Block 默認(rèn)存儲棧中。
ARC 環(huán)境下:訪問外界變量的 Block 默認(rèn)存儲在堆中(實際是放在棧區(qū),然后ARC情況下自動又拷貝到堆區(qū)),自動釋放。

4、防止 Block 循環(huán)引用
Block 循環(huán)引用的情況:
某個類將 block 作為自己的屬性變量,然后該類在 block 的方法體里面又使用了該類本身,如下:

self.someBlock = ^(Type var){
    [self dosomething];
};

解決辦法:

(1)ARC 下:使用 __weak

__weak typeof(self) weakSelf = self;
self.someBlock = ^(Type var){
   [weakSelf dosomething];
};

(2)MRC 下:使用 __block

__block typeof(self) blockSelf = self;
self.someBlock = ^(Type var){
   [blockSelf dosomething];
};

值得注意的是,在ARC下,使用 __block 也有可能帶來的循環(huán)引用,如下:

// 循環(huán)引用 self -> _attributBlock -> tmp -> self
typedef void (^Block)();
@interface TestObj : NSObject
{
    Block _attributBlock;
}
@end

@implementation TestObj
- (id)init {
    self = [super init];
    __block id tmp = self;
    self.attributBlock = ^{
        NSLog(@"Self = %@",tmp);
        tmp = nil;
   };
}

- (void)execBlock {
    self.attributBlock();
}
@end

// 使用類
id obj = [[TestObj alloc] init];
[obj execBlock]; // 如果不調(diào)用此方法,tmp 永遠(yuǎn)不會置 nil,內(nèi)存泄露會一直在

5、有時候我們經(jīng)常也會被問到block為什么 常使用copy關(guān)鍵字?

block 使用 copy 是從 MRC遺留下來的“傳統(tǒng)”,在 MRC 中,方法內(nèi)部的 block 是在棧區(qū)的,使用 copy 可以把它放到堆區(qū).在 ARC 中寫不寫都行:對于 block 使用 copy 還是 strong 效果是一樣的,但寫上 copy 也無傷大雅,還能時刻提醒我們:編譯器自動對 block 進(jìn)行了 copy 操作。
如果不寫 copy ,該類的調(diào)用者有可能會忘記或者根本不知道“編譯器會自動對 block 進(jìn)行了 copy 操作”


更多:iOS面試題合集

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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