Block (代碼塊) 是將程式碼片段封裝為一級物件的機制,又稱匿名函數或閉包。iOS 4+ 引入,現已成為回調、非同步、集合遍歷、動畫等場景的標準方案。
兩大決定因素:回傳值型別 + 參數列表
// 無參無回傳 void (^SimpleBlock)(void); // 有參有回傳 int (^AddBlock)(int a, int b); // 使用 typedef 簡化 typedef void (^VoidBlock)(void); typedef int (^IntIntBlock)(int, int); VoidBlock block1; IntIntBlock block2;
// 封裝語法:^ 參數列表 { 程式碼 }
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 修飾符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 執行期間物件存活 |
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 控制項、簡單動作 | 複雜組件、多回調、資料源 | 非同步完成、動畫、簡單單一回調 |
copy 將棧上 Block 複製到堆疊,Block 屬性必須用 copy__block 變數持有自身引用dispatch_async(queue, ^{ ... }) 核心即 BlockBlock 以其程式碼即資料的強大抽象,徹底改變了 Objective-C 的非同步與回調編程範式。掌握 捕獲語意、記憶體管理舞步、型別聲明技巧 與 三大回調模式選型邏輯,能讓你寫出更簡潔、更安全、更具表達力的現代 Objective-C 代碼。