iOS 4+引入,將代碼片段封裝為對象,可作為參數傳遞、存儲、延遲調用。本質是匿名函數,捕獲上下文變量。
類型由返回值類型與參數列表決定:
// 封裝:^ 參數列表 { 代碼體 }
VoidBlock logBlock = ^{ NSLog(@"Hello Block"); };
IntBlock addBlock = ^(int a, int b) { return a + b; };
// 調用
logBlock(); // 輸出 "Hello Block"
int sum = addBlock(3, 5); // sum = 8
// Block變量可賦值給同類型變量
IntBlock anotherAdd = addBlock;
NSLog(@"%d", anotherAdd(10, 20)); // 30
默認行為:按值捕獲(複製)局部變量,Block內使用的是副本。
__block int modifier = 10; // 使用__block修飾
VoidBlock block = ^{
NSLog(@"modifier = %d", modifier); // 捕獲副本,值為10
};
modifier = 20; // 修改原變量
block(); // 仍輸出10 —— 副本未變
__block修飾符:引用捕獲__block int modifier = 10;
VoidBlock block = ^{
NSLog(@"modifier = %d", modifier); // 共享同一內存
};
modifier = 20;
block(); // 輸出20 —— 讀取最新值
// Block內也可修改
__block int counter = 0;
VoidBlock increment = ^{ counter++; };
increment(); // counter = 1
應用場景:Block需修改外部局部變量、或需讀取最新值時使用__block。
優於Target-Action/Delegate:無需分離target與action,代碼內聯定義,上下文自動捕獲,每個回調獨立。
typedef enum : NSUInteger {
SwitchStateOff, SwitchStateOn
} SwitchState;
typedef void (^SwitchBlock)(SwitchState state);
@interface SwitchBlockBased : NSObject
@property (nonatomic, assign, readonly) SwitchState currentState;
@property (nonatomic, copy) SwitchBlock changeStateHandler; // copy修飾Block
@end
// 使用者:Room類
@interface Room : NSObject
@property (strong, nonatomic) Light *light;
@property (strong, nonatomic) SwitchBlockBased *switch;
@end
@implementation Room
- (instancetype)init {
self = [super init];
if (self) {
self.light = [[Light alloc] init];
self.switch = [[SwitchBlockBased alloc] init];
// 關鍵:__weak __block 打破循環引用
__weak __block Room *weakSelf = self;
self.switch.changeStateHandler = ^(SwitchState state) {
if (state == SwitchStateOff)
[weakSelf.light turnOff];
else
[weakSelf.light turnOn];
};
}
return self;
}
@end
copy:將棧上Block複製到堆上,延長生命週期__weak __block typeof(self) weakSelf = self; 在Block內使用weakSelfcompletionHandler| 模式 | Target-Action | Delegate委托 | Block |
|---|---|---|---|
| 綁定方式 | target + selector | delegate對象 + 協議方法 | Block變量 |
| 參數靈活性 | 固定(sender) | 協議定義,可攜帶豐富參數 | 完全自定義 |
| 多實例隔離 | 困難 | 需在方法內判斷sender | 天然隔離,每個Block獨立 |
| 代碼組織 | 分散 | 分散 | 內聯,上下文清晰 |
| 適用場景 | 簡單控件 | 複雜組件、多回調事件 | 異步操作、動畫、網絡請求、簡單回調 |