首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

Objective-C Block 捕獲外部變量完解析:`__block`、拷貝語義與內存管理

     編輯:關於C語言

Objective-C Block 捕獲外部變量完解析:`__block`、拷貝語義與內存管理

Block 是 C 語言級別的語法與運行機制,兼容 C/C++/Objective-C。除可執行代碼外,還攜帶綁定棧/堆內存的變量(狀態數據)。常作為回調傳遞,代碼與數據封裝在一起。

1. Block 內部可訪問外部變量

Block 內可直接使用外部作用域變量。但默認按值捕獲(拷貝):Block 內部持有該變量的一份只讀副本(`const`)。外部變量修改不影響 Block 內副本,Block 內也不能修改副本(編譯錯誤)。

int a = 10;
void (^blk)() = ^{
    // a 在此處為 const int,不可修改
    NSLog(@"%d", a); // 10
};
a = 20;
blk(); // 仍輸出 10,捕獲的是創建時的值

2. 同名局部變量遮蔽

Block 內定義同名變量會遮蔽捕獲的外部變量。

3. `__block` 修飾符:可讀寫捕獲

給外部變量加 `__block`,Block 將捕獲其地址引用而非值拷貝。Block 內可修改,修改對外部可見;外部修改對 Block 可見。實現機制:`__block` 變量被包裝在一個結構體中,引用計數管理,隨 Block 在棧/堆間移動。

__block int a = 10;
void (^blk)() = ^{
    a = 20; // 允許修改
    NSLog(@"%d", a);
};
blk(); // 20
NSLog(@"%d", a); // 20,外部也被修改

4. 靜態/全局變量特殊規則

  • 靜態/全局變量無論是否加 `__block`,Block 均捕獲其地址(直接引用),可直接修改。
  • 因為它們存儲在數據段,生命週期覆蓋整個程序,無拷貝必要。

5. 常量對象(如 `NSString *`)捕獲細節

  • 未加 `__block`:捕獲指針值(淺拷貝),Block 內不可修改指針指向(編譯錯),但可調用對象方法(若對象可變)。
  • 加 `__block`:捕獲指針變量地址,Block 內可修改指針指向(如 `str = @"new"`),外部可見。

6. 內存管理核心規則

  1. Block 創建在棧上。若需超出創建作用域使用,必須 `` 或 `[block copy]` 移至堆上。
  2. Block_copy 會 retain 捕獲的 `__block` 變量及對象指針(強引用)。
  3. Block_release / `release` 對應釋放。
  4. ARC 環境下自動處理,但循環引用需手動 `__weak` 打破。

7. 總結表

變量類型無 `__block`有 `__block`
局部自動變量值拷貝(只讀)地址引用(可讀寫)
靜態/全局變量地址引用(可讀寫)地址引用(可讀寫)
常量對象指針指針值拷貝(不可改指向)指針地址引用(可改指向)

8. 最佳實踐建議

  • 默認不加 `__block`,保證值語義安全。
  • 確需在 Block 內修改外部局部變量時加 `__block`。
  • 捕獲 `self` 易導致循環引用,用 `__weak typeof(self) weakSelf = self;` 在 Block 內用 `weakSelf`。
  • Block 參數傳遞給 API 時,若 API 會異步持有,確保 Block 已 copy 到堆(ARC 下自動)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved