Block 內部訪問實例變量 (如 `self.name`、 `_ivar`、 `self->property`) 會**隱式捕獲 `self`** 並 `retain` (ARC) / `copy` (MRC)。
若該 Block 被作為屬性持有、或傳遞給持有 self 的對象 (如網絡請求回調、通知中心、動畫完成塊),形成:
self → Block (copy/retain) → self (循環)
導致引用計數永不歸零,`dealloc` 永不調用。
// 錯誤
[self doSomethingWithCompletion:^{
[self updateUI]; // 隱式捕獲 self
}];
// 正確:__weak 弱引用打破循環
__weak typeof(self) weakSelf = self;
[self doSomethingWithCompletion:^{
__strong typeof(self) strongSelf = weakSelf; // 升級防止執行時釋放
if (strongSelf) {
[strongSelf updateUI];
}
}];
__block typeof(self) blockSelf = self; // __block 不 retain
[self doSomethingWithCompletion:^{
[blockSelf updateUI];
}];
// 注意:MRC 下 __block 不增加引用計數,但需確保 block 執行時 self 仍存活
// 通常配合手動 retain/release 管理 block 生命周期
| 場景 | 典型代碼 | 修正 |
|---|---|---|
| 網絡請求回調 | `[session dataTaskWithRequest:req completion:^(...) { self.data = ...; }]` | `__weak typeof(self) ws = self;` |
| 通知中心觀察者 | `[[NSNotificationCenter defaultCenter] addObserverForName:@"" object:nil queue:mainQueue usingBlock:^(NSNotification* n) { [self handle]; }]` | Block 捕獲 self,需 `__weak`;或用方法選擇器 `addObserver:selector:` |
| 動畫完成塊 | `[UIView animateWithDuration:0.3 animations:^{ self.view.alpha = 0; } completion:^(BOOL f) { [self remove]; }]` | `__weak` + `strongSelf` |
| GCD 延遲執行 | `dispatch_after(time, queue, ^{ [self doLater]; });` | `__weak` + `strongSelf` |
| 屬性持有 Block | `@property (copy) void(^completionBlock)(void);` | Block 內用 `__weak self`;或 `dealloc` 中置 nil |