首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

iOS dealloc 不調用:Block 循環引用導致無法釋放,__weak/__block 解決

     編輯:程式設計綜合問答

問題現象

  • ViewController 無 Timer、無 delegate retain。
  • Push 後手動 release (MRC) / 彈出 (ARC) 。
  • `dealloc` **不執行**,對象洩漏。

核心原因:Block 捕獲 self 形成循環引用

Block 內部訪問實例變量 (如 `self.name`、 `_ivar`、 `self->property`) 會**隱式捕獲 `self`** 並 `retain` (ARC) / `copy` (MRC)。

若該 Block 被作為屬性持有、或傳遞給持有 self 的對象 (如網絡請求回調、通知中心、動畫完成塊),形成:


self → Block (copy/retain) → self  (循環)

導致引用計數永不歸零,`dealloc` 永不調用。

解決方案

ARC 環境 (現代標準)


// 錯誤
[self doSomethingWithCompletion:^{
    [self updateUI]; // 隱式捕獲 self
}];

// 正確:__weak 弱引用打破循環
__weak typeof(self) weakSelf = self;
[self doSomethingWithCompletion:^{
    __strong typeof(self) strongSelf = weakSelf; // 升級防止執行時釋放
    if (strongSelf) {
        [strongSelf updateUI];
    }
}];

MRC 環境 (舊代碼)


__block typeof(self) blockSelf = self; // __block 不 retain
[self doSomethingWithCompletion:^{
    [blockSelf updateUI];
}];
// 注意:MRC 下 __block 不增加引用計數,但需確保 block 執行時 self 仍存活
// 通常配合手動 retain/release 管理 block 生命周期

常見 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

調試技巧:定位洩漏對象

  1. Instruments → Leaks**:運行 App,操作可疑頁面,標記生成堆棧,顯示洩漏對象、分配調用鏈。
  2. Debug Memory Graph (Xcode 8+)**:調試時點擊「Debug Memory Graph」圖標,查看對象引用關係圖,**循環引用顯示為雙向箭頭**。
  3. 靜態分析**:`Product → Analyze` (Shift+Cmd+B),Clang 靜態分析器會報警「Capture of 'self' in block creates retain cycle」。

最佳實踐

  1. **默認 Block 內用 `__weak self`** (ARC),形成肌肉記憶。
  2. **屬性修飾符**:Block 屬性用 `copy` (非 `strong`),確保 Block 在堆上。
  3. **統一封裝**:基類提供 `weakSelf` / `strongSelf` 宏或分類方法。
  4. **定期 Leaks 檢測**納入 CI 流程。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved