10.1 Block:闭包的方括号版本
在很久以前,OC 想要回调,只能靠 Delegate。
为了回传一个状态,你得写协议、设代理、实现方法……太累了。
后来,Apple 引入了 Blocks(^)。
它的语法可以说是 OC 中最反人类的设计之一(著名的 fuckingblocksyntax.com 就是为此而生):
returnType (^blockName)(parameterTypes) = ^returnType(parameters) {...};
但是,它让代码可以在原地执行回调。
[manager fetchWeathersWithCompletion:^(NSArray *weathers, NSError *error) {
// 收到数据,直接在这里处理
NSLog(@"Fetched: %@", weathers);
}];
这极大地简化了异步编程的逻辑。需要注意的是 循环引用(Retain Cycle):在 Block 里用 self,一定要先 __weak typeof(self) weakSelf = self;。
10.2 GCD:把线程扔进队列
与 Blocks 一起诞生的,是 Grand Central Dispatch (GCD)。
在 GCD 之前,我们用 NSThread 或 NSOperation。
GCD 告诉我们:忘掉线程吧。你只需要关心队列(Queue)。
- 串行队列 (Serial Queue): 一个接一个做。
- 并发队列 (Concurrent Queue): 大家一起做。
- 主队列 (Main Queue): 专门负责更新 UI 的(UI 只能在主线程更新)。
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 1. 在后台干脏活累活(下载图片)
UIImage *img = [self downloadImage];
dispatch_async(dispatch_get_main_queue(), ^{
// 2. 回到主线程更新 UI
self.imageView.image = img;
});
});
这套 dispatch_async 的模板代码,是每一个 OC 程序员的肌肉记忆。
虽然 Swift 如今有了 async/await,但 GCD 依然是底层最坚实的基石。