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

Objective-C 教程 6:Block 代碼塊回調機制完整掌握

     編輯:C 語言入門

Block 核心概念

Block (代碼塊) 是將程式碼片段封裝為一級物件的機制,又稱匿名函數或閉包。iOS 4+ 引入,現已成為回調、非同步、集合遍歷、動畫等場景的標準方案。

Block 型別聲明

兩大決定因素:回傳值型別 + 參數列表

// 無參無回傳
void (^SimpleBlock)(void);

// 有參有回傳
int (^AddBlock)(int a, int b);

// 使用 typedef 簡化
typedef void (^VoidBlock)(void);
typedef int (^IntIntBlock)(int, int);

VoidBlock block1;
IntIntBlock block2;

Block 封裝與調用

// 封裝語法:^ 參數列表 { 程式碼 }
VoidBlock greet = ^{ NSLog(@"Hello Block!"); };
IntIntBlock add = ^(int a, int b) { return a + b; };

// 調用
greet();           // 輸出: Hello Block!
int sum = add(3, 5); // sum = 8

// Block 變數可賦值給同型別變數
IntIntBlock anotherAdd = add;
NSLog(@"%d", anotherAdd(10, 20)); // 30

Block 捕獲變數與 __block 修飾符

預設行為:值捕獲 (Copy)

typedef void (^VoidBlock)(void);
VoidBlock globalBlock;

void func1() {
    int a = 10;
    globalBlock = ^{ NSLog(@"a = %d", a); }; // 捕獲 a 的副本 (值 10)
    a = 20; // 不影響 Block 內的 a
}

void func2() {
    globalBlock(); // 輸出: a = 10
}

__block:引用捕獲 (共享儲存)

void func1() {
    __block int a = 10; // 標記為 __block
    globalBlock = ^{ NSLog(@"a = %d", a); };
    a = 20; // 修改共享儲存
}

void func2() {
    globalBlock(); // 輸出: a = 20
}

記憶體管理:打破循環引用

__weak __block typeof(self) weakSelf = self; // 雙重保險
self.completionBlock = ^{
    [weakSelf doSomething]; // weakSelf 可能為 nil,安全
    // 或
    __strong typeof(self) strongSelf = weakSelf; // 臨時強引用
    if (strongSelf) { [strongSelf doSomething]; }
};
修飾符捕獲方式生命週期影響適用場景
無 (預設)值複製不延長變數壽命基本型別、不可變物件
__block引用共享不延長 (ARC 下 Block 複製到堆疊時會 retain)需在 Block 內修改外部變數
__weak弱引用不延長,物件釋放自動變 nil打破 self ↔ Block 循環引用
__strong強引用延長壽命確保 Block 執行期間物件存活

Block 回調介面實戰:開關元件

元件定義

typedef NS_ENUM(NSUInteger, SwitchState) {
    SwitchStateOff, SwitchStateOn
};

typedef void (^SwitchStateBlock)(SwitchState state);

@interface SwitchB : NSObject
@property (nonatomic, assign, readonly) SwitchState currentState;
@property (nonatomic, copy) SwitchStateBlock changeStateBlockHandle; // Block 屬性用 copy
@end

使用者端設定回調

@interface Room : NSObject
@property (strong, nonatomic) Light *lightA;
@property (strong, nonatomic) SwitchB *s;
@end

@implementation Room
- (instancetype)init {
    self = [super init];
    if (self) {
        self.lightA = [[Light alloc] init];
        self.s = [[SwitchB alloc] init];
        
        __weak typeof(self) weakSelf = self; // 打破循環引用
        self.s.changeStateBlockHandle = ^(SwitchState state) {
            // 使用 weakSelf 避免 self 持有 Block,Block 持有 self
            if (state == SwitchStateOff) {
                [weakSelf.lightA turnOff];
            } else {
                [weakSelf.lightA turnOn];
            }
        };
    }
    return self;
}
@end

三種回調模式終極比較

維度Target-Action委託回調Block 回調
靈活度高 (自訂 Selector)中 (協定固定)極高 (內聯程式碼)
參數豐富度低 (單一 sender)高 (協定定義)高 (Block 簽名)
多組件隔離靠 Selector 區分需在方法內判斷 sender天然隔離 (每組件一 Block)
程式碼局部性分離 (分散在各方法)分離 (委託方法)高 (設定處即實作)
記憶體管理簡單 (weak target)需 weak delegate需 weakSelf/strongSelf 舞步
除錯體驗堆疊難追蹤清晰良好 (內聯)
適用場景UI 控制項、簡單動作複雜組件、多回調、資料源非同步完成、動畫、簡單單一回調

Block 進階技巧

  1. 全域/靜態 Block:無捕獲變數時編譯器優化為全域常數,無需 copy
  2. Block 複製規則:copy 將棧上 Block 複製到堆疊,Block 屬性必須用 copy
  3. 遞迴 Block:需宣告 __block 變數持有自身引用
  4. GCD 併發:dispatch_async(queue, ^{ ... }) 核心即 Block

結語

Block 以其程式碼即資料的強大抽象,徹底改變了 Objective-C 的非同步與回調編程範式。掌握 捕獲語意、記憶體管理舞步、型別聲明技巧 與 三大回調模式選型邏輯,能讓你寫出更簡潔、更安全、更具表達力的現代 Objective-C 代碼。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved