Blocks(塊) 是 C 語言層面的閉包,支援捕獲外部變數、作為參數傳遞、延遲執行。Apple 於 OS X 10.6 / iOS 4.0 引入,現為 Grand Central Dispatch (GCD)、動畫 API、網路回調的標準寫法。本質上是「帶有自動捕獲環境的匿名函數」,比傳統 C 函數指標更強大、更安全。
| 特性 | C 函數指標 | Blocks |
|---|---|---|
| 捕獲區域變數 | ❌ 需手動傳遞 context 指標 | ✅ 自動捕獲(值複製或 __block 參考) |
| 語法靈活度 | 僅能指向既有函數 | 可內聯定義匿名邏輯 |
| 記憶體管理 | 手動 | ARC 自動管理(需 copy 移至堆區) |
| 型別安全 | 較弱 | 編譯期完整檢查參數/返回型別 |
typedef int (^SumBlock)(int a, int b); // 可重複使用的型別名
// 無參無回傳
void (^simpleBlock)(void) = ^{ NSLog(@"Hello Block"); };
// 有參有回傳
int (^addBlock)(int, int) = ^(int a, int b) { return a + b; };
// 使用 typedef
SumBlock sum = ^(int a, int b) { return a + b; };
simpleBlock(); // 輸出 Hello Block
int result = addBlock(3, 5); // result = 8
__block 修飾詞:打破值捕獲限制預設 Blocks 以值捕獲外部區域變數(唯讀)。加上 __block 可讓 Block 讀寫同一記憶體位址:
__block int counter = 0;
void (^increment)(void) = ^{ counter++; };
increment(); // counter = 1
increment(); // counter = 2
同一場景,程式碼更緊湊、就地定義回調邏輯。
#import
@class Dog;
typedef void (^DogBarkBlock)(Dog *dog, NSInteger count);
@interface Dog : NSObject
@property (nonatomic, assign) NSInteger dogID;
@property (nonatomic, copy) DogBarkBlock barkHandler; // 必須 copy
- (instancetype)initWithID:(NSInteger)id;
@end
#import "Dog.h"
@implementation Dog {
NSTimer *_timer;
NSInteger _barkCount;
}
- (instancetype)initWithID:(NSInteger)id {
self = [super init];
if (self) {
_dogID = id;
_barkCount = 0;
_timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(timerFired:)
userInfo:nil
repeats:YES];
}
return self;
}
- (void)timerFired:(NSTimer *)timer {
_barkCount++;
if (self.barkHandler) {
self.barkHandler(self, _barkCount); // 直接呼叫 Block
}
}
- (void)dealloc {
[_timer invalidate];
_timer = nil;
// ARC 自動釋放 barkHandler (copy 的 Block)
}
@end
Dog *dog = [[Dog alloc] initWithID:1024];
dog.barkHandler = ^(Dog *d, NSInteger count) {
NSLog(@"[Block 回調] 狗 %ld 第 %ld 次吠叫", (long)d.dogID, (long)count);
};
// 為了讓 Timer 運作,命令列專案需跑 RunLoop
[[NSRunLoop currentRunLoop] run];
copy:Block 建立在棧上,copy 將其複製到堆區,隨物件生命週期釋放。self 時,務必用 __weak 或 __block 弱引用:
__weak typeof(self) weakSelf = self;
self.completionHandler = ^{
[weakSelf doSomething]; // 安全
};
dispatch_async(queue, ^{ ... });[UIView animateWithDuration:0.3 animations:^{ ... }]dataTaskWithRequest:completionHandler:^(data, resp, err){ ... }[array enumerateObjectsUsingBlock:^(obj, idx, stop){ ... }]Blocks 讓 Objective-C 擁有了現代語言的閉包能力,極大簡化了非同步、回調、集合操作的程式碼。掌握 copy、__block、弱引用破環三大記憶體管理要訣,即可安全、高效地在專案中大量使用 Blocks,甚至完全替代簡單的 Delegate 模式。