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

Objective-C Block 深度解析:語法、捕獲語義、ARC/MRC 內存管理、GCD 實戰

     編輯:關於C語言

Block (閉包) 是 Objective-C 2.0 引入的匿名函數塊,賦予 C 語言函數式編程能力,也是 GCD、動畫、網絡回調、枚舉器的核心載體。本文系統講解聲明定義語法、變量捕獲規則、__block 修飾符、複製機制、ARC/MRC 內存管理、類型定義與 GCD 實戰模式。

一、語法速查表

二、變量捕獲語義

void demo_capture() {
    int a = 10;
    const int b = 20;
    static int c = 30;
    int arr[3] = {1,2,3};
    
    // 1. 自動變量:值捕獲 (只讀複制)
    void (^blk1)() = ^{
        NSLog(@"a=%d, b=%d, c=%d, arr[0]=%d", a, b, c, arr[0]);
        // a=10, b=20, c=30, arr[0]=1  (編譯時複制)
    };
    
    a = 100;  // 修改不影響 blk1 內的副本
    blk1();   // 仍輸出 10
    
    // 2. __block 修飾:引用捕獲 (可讀寫共享)
    __block int x = 42;
    void (^blk2)() = ^{
        x = 100;
        NSLog(@"x=%d", x);  // 100
    };
    blk2();
    NSLog(@"outer x=%d", x);  // 100,外部也變了
    
    // 3. 靜態/全局變量:直接引用 (無需 __block)
    // 4. 數組/結構體:退化為指針,捕獲地址 (淺捕獲)
}

捕獲規則總結

形式語法示例
聲明變量返回類型 (^名稱)(參數列表);int (^add)(int, int);
定義字面量^返回類型(參數) { 體 }^int(int a, int b) { return a+b; }
類型定義typedef 返回類型 (^類型名)(參數);typedef int (^AddBlock)(int, int);
作為參數void func(AddBlock block);func(^int(int a,int b){return a+b;});
作為返回值AddBlock makeAdder(int base);見下文

三、Block 內存管理:棧→堆複製

// Block 字面量初始在棧上 (栈 Block)
// 超出作用域必須 copy 到堆
void (^stackBlk)() = ^{ NSLog(@"stack"); };

// ARC 環境:自動處理
// - 作為參數傳遞/賦值給強屬性 → 自動 copy
// - 返回 Block → 編譯器插入 copy (需標註 NS_RETURNS_RETAINED 或靜態分析)

// MRC 環境:手動管理
void (^heapBlk)() = [stackBlk copy];  // 保留塊
[heapBlk release];                    // 釋放

// 屬性聲明
@property (nonatomic, copy) void (^completion)(void);  // copy 語義必須

複製規則口訣

  • 棧 Block:作用域結束銷毀,離開定義作用域前必須 copy。
  • 全局 Block:字面量在數據段,copy 無效果 (no-op)。
  • ARC:copy 屬性、強引用賦值、跨函數返回 → 自動 copy。
  • MRC:Block_copy() / Block_release() 配對。

四、__block 底層實現與循環引用防範

// __block 變量被包裝為堆對象
// 結構體包含:轉發指針、引用計數、實際值
// Block copy 時會 retain __block 對象
// Block release 時 release __block 對象

// 循環引用典型場景
__block typeof(self) weakSelf = self;  // MRC/手動弱引用
self.completion = ^{
    [weakSelf doSomething];  // 不 retain self
};

// ARC 環境推薦
__weak typeof(self) weakSelf = self;
self.completion = ^{
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) [strongSelf doSomething];
};

五、GCD 實戰模式

// 1. 異步任務 + 主線程回調
dispatch_async(dispatch_get_global_queue(0,0), ^{
    id result = [self heavyComputation];
    dispatch_async(dispatch_get_main_queue(), ^{
        [self updateUIWithResult:result];
    });
});

// 2. 併發組等待多任務
dispatch_group_t group = dispatch_group_create();
for (NSURL *url in urls) {
    dispatch_group_enter(group);
    [self downloadURL:url completion:^{
        dispatch_group_leave(group);
    }];
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    NSLog(@"All done");
});

// 3. 信號量限制併發度
dispatch_semaphore_t sema = dispatch_semaphore_create(3);
for (id task in tasks) {
    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    dispatch_async(queue, ^{
        [task execute];
        dispatch_semaphore_signal(sema);
    });
}

六、Block 與 C++ Lambda 對比

變量類型默認捕獲可修改__block 效果
自動局部變量 (auto)值捕獲 (複制)❌引用捕獲 (共享存儲)
static / 全局引用捕獲 (地址)✅無效果 (已是引用)
const 自動變量值捕獲❌引用捕獲 (可去 const)
數組 / 結構體指針捕獲 (淺)✅ 修改內容指針本身可重綁定

七、避坑清單

  1. Block 內強引用 self → 循環引用,用 __weak 打破。
  2. Block 字面量直接賦值給 weak 屬性 → 即刻銷毀,必須先 copy 或用強引用中轉。
  3. __block 變量在多線程並發修改 → 數據競態,需加鎖或用原子操作。
  4. Block 作為 C 回調傳遞:轉換為函數指針不可行,需包裝上下文結構體 + trampoline 函數。
  5. 調試時打印 Block:po block 顯示簽名,p (void*)block 看地址判斷棧/堆。

Block 將「代碼作為數據」在 Objective-C 落地,配合 GCD 構建了現代 iOS/macOS 異步編程的基石。掌握捕獲語義、複製機制、弱引用打破循環,是寫出無崩潰、無洩漏並發代碼的必修課。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
特性ObjC BlockC++ Lambda
捕獲語法隱式值捕獲 + __block顯式 [=], [&], [x]
可變捕獲__blockmutable 關鍵字
內存模型棧→堆 copy、ARC/MRC 管理值語義、自動析構、std::function 擦除類型
類型擦除id / void (^)(void)std::function
異步框架GCD / NSOperationstd::thread / std::async / 協程