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

Objective-C Block 深度解析:閉包特性、循環引用與 GCD/NSOperation 實戰

     編輯:關於C語言

Block 本質:帶自動捕獲變量的匿名函數

Block 是 C 語言擴展,本質是一個結構體指針,內部包含:

  • 函數指針(執行代碼)
  • 捕獲的變量副本或引用
  • 描述信息(簽名、佈局等)

類似其他語言的閉包:可訪問定義作用域內的局部變量。

Block 基礎使用三步驟


// 1. 定義類型(可選,簡化語法)
typedef void(^MyBlock)(int, int);

// 2. 定義並賦值(捕獲外部變量)
int factor = 10;
MyBlock block = ^(int a, int b) {
    printf("Result: %d\n", (a + b) * factor);  // 捕獲 factor
};

// 3. 執行
block(3, 4);  // 輸出 70

優於函數指針的優勢

  • 內聯捕獲上下文:無需額外參數傳遞上下文結構體。
  • 可作參數/返回值:實現回調、延遲執行、鏈式調用。
  • 語法輕量:^返回類型(參數){體} 即時定義。

屬性修飾符:copy 是鐵律


@property (nonatomic, copy) void(^completionBlock)(BOOL success);

原因:Block 創建在棧上,離開作用域即銷毀。copy 將其從棧拷貝到堆,延長生命周期。ARC 下自動處理,MRC 必須手動 [block copy]/release。

循環引用陷阱與弱引用打破

經典循環:self → Block → self


// 錯誤示例
self.block = ^{
    [self doSomething];  // Block 強引用 self
};
// self 強引用 block (屬性 copy) → 循環

標準解法:weak-strong dance


__weak typeof(self) weakSelf = self;
self.block = ^{
    __strong typeof(weakSelf) strongSelf = weakSelf;
    if (strongSelf) {
        [strongSelf doSomething];
    }
};
  • __weak:不增加引用計數,對象釋放自動置 nil。
  • __strong:在 Block 內部臨時持有,防止執行過程中對象被釋放。

GCD Block:為什麼不會循環引用?


dispatch_async(queue, ^{
    [self doSomething];  // 直接用 self 安全
});

核心原因:GCD Block 執行完即刻釋放,不會被長期持有。dispatch_async 內部不持有 Block 的強引用(僅在隊列執行期間臨時持有),self 也不持有 Block。無「雙向強引用」,無循環。

NSOperation Block:會循環引用,但可控


NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
    [self doSomething];  // 潛在循環
}];
[queue addOperation:op];
⚠ 會產生循環引用! Operation 被隊列強引用,隊列常作為屬性被 self 強引用 → self → queue → operation → block → self。

但通常安全:Operation 執行完成後自動從隊列移除並釋放,打破循環。長時間運行或取消操作時需注意,可在 Block 內用 weakSelf。

Block 變量捕獲規則

變量類型捕獲方式可修改性
局部基本類型值捕獲(複製)不可修改(除非加 __block)
局部對象指針引用捕獲(retain)可修改指向對象內容
static/全局變量直接訪問地址可修改
__block 修飾引用捕獲(共享存儲)可修改變量本身

__block 進階:ARC 下的引用語義


__block id obj = [[MyClass alloc] init];
// Block 內修改 obj 指向新對象
block = ^{
    obj = [MyClass new];  // 合法,共享存儲
};

ARC 下 __block 對對象指針會 retain,Block 拷貝到堆時會 retain 捕獲的 __block 變量指向的對象。

最佳實踐清單

  1. Block 屬性必加 copy。
  2. Block 內用 self 必做 weakSelf(除 GCD 短時任務)。
  3. 需修改外部局部變量加 __block。
  4. 長時間運行/可取消的 Operation Block 同樣用 weakSelf。
  5. 避免在 Block 內大量捕獲大對象,增加內存壓力。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved