在 Objective-C 中硼瓣,block
是一種匿名函數(shù),可以捕獲上下文中的變量末患。為了確保 block
在內(nèi)存管理中的正確性牲证,通常使用 copy
修飾符哮针。以下是詳細(xì)原因和解釋:
1. block 的內(nèi)存管理
-
block 的類型:
-
NSGlobalBlock
:存儲(chǔ)在全局區(qū),不捕獲任何外部變量坦袍。 -
NSStackBlock
:存儲(chǔ)在棧區(qū)诚撵,捕獲外部變量。 -
NSMallocBlock
:存儲(chǔ)在堆區(qū)键闺,由棧區(qū) block 復(fù)制而來(lái)。
-
-
默認(rèn)行為:
- 當(dāng) block 捕獲外部變量時(shí)澈驼,默認(rèn)是
NSStackBlock
辛燥,存儲(chǔ)在棧區(qū)。 - 棧區(qū)的 block 在作用域結(jié)束后會(huì)被釋放缝其,如果此時(shí)嘗試訪問該 block挎塌,會(huì)導(dǎo)致崩潰。
- 當(dāng) block 捕獲外部變量時(shí)澈驼,默認(rèn)是
2. 為什么用 copy
修飾
-
將 block 從棧復(fù)制到堆:
- 使用
copy
修飾符可以將NSStackBlock
復(fù)制為NSMallocBlock
内边,存儲(chǔ)在堆區(qū)榴都。 - 堆區(qū)的 block 生命周期由引用計(jì)數(shù)管理,可以安全地在作用域外使用漠其。
- 使用
-
避免野指針:
- 如果不使用
copy
嘴高,棧區(qū)的 block 在作用域結(jié)束后會(huì)被釋放竿音,后續(xù)訪問會(huì)導(dǎo)致野指針問題。
- 如果不使用
-
ARC 下的行為:
- 在 ARC(自動(dòng)引用計(jì)數(shù))環(huán)境下拴驮,
copy
是默認(rèn)行為春瞬,即使不顯式使用copy
,編譯器也會(huì)自動(dòng)將 block 復(fù)制到堆區(qū)套啤。 - 但在 MRC(手動(dòng)引用計(jì)數(shù))環(huán)境下宽气,必須顯式使用
copy
。
- 在 ARC(自動(dòng)引用計(jì)數(shù))環(huán)境下拴驮,
3. 代碼示例
-
MRC 環(huán)境下:
typedef void (^MyBlock)(void); @interface MyClass : NSObject @property (nonatomic, copy) MyBlock block; @end @implementation MyClass - (void)setupBlock { int value = 10; self.block = [^{ NSLog(@"Value: %d", value); } copy]; // 必須使用 copy } @end
-
ARC 環(huán)境下:
@interface MyClass : NSObject @property (nonatomic, copy) MyBlock block; @end @implementation MyClass - (void)setupBlock { int value = 10; self.block = ^{ NSLog(@"Value: %d", value); }; // ARC 下會(huì)自動(dòng) copy } @end
4. 注意事項(xiàng)
-
循環(huán)引用:
- 使用
copy
修飾 block 時(shí)潜沦,如果 block 捕獲了self
萄涯,可能導(dǎo)致循環(huán)引用。 - 解決方法:使用
__weak
弱引用打破循環(huán)唆鸡。__weak typeof(self) weakSelf = self; self.block = ^{ __strong typeof(weakSelf) strongSelf = weakSelf; [strongSelf doSomething]; };
- 使用
-
性能影響:
-
copy
操作會(huì)涉及內(nèi)存分配和復(fù)制涝影,可能對(duì)性能有輕微影響。 - 但對(duì)于大多數(shù)場(chǎng)景喇闸,這種影響可以忽略袄琳。
-
5. 總結(jié)
- 在 Objective-C 中,使用
copy
修飾 block 是為了將 block 從棧區(qū)復(fù)制到堆區(qū)燃乍,確保其生命周期和內(nèi)存安全唆樊。 - 在 MRC 環(huán)境下必須顯式使用
copy
,而在 ARC 環(huán)境下編譯器會(huì)自動(dòng)處理刻蟹。 - 使用
copy
時(shí)需注意循環(huán)引用問題逗旁,可以通過弱引用解決。