Objective-C Blocks and GCD by thebushidocollective/han
npx skills add https://github.com/thebushidocollective/han --skill 'Objective-C Blocks and GCD'Blocks 是 Objective-C 的闭包实现,提供了能够捕获周围上下文的匿名函数。Grand Central Dispatch (GCD) 是 Apple 用于管理并发操作的低级 API,它使用调度队列而非直接操作线程。
Blocks 支持函数式编程模式、回调以及简洁的异步 API 设计。GCD 通过将线程管理抽象为队列,自动将工作分配到可用的 CPU 核心上,从而简化了并发编程。二者共同构成了现代 Objective-C 并发编程的基础。
本技能涵盖 Block 的语法和语义、捕获行为、GCD 队列和调度函数、同步原语以及编写安全并发代码的模式。
Blocks 是一等对象,封装了代码并可以捕获其定义作用域中的变量。
// 基本 Block 语法
void (^simpleBlock)(void) = ^{
NSLog(@"Hello from block");
};
simpleBlock(); // 调用 Block
// 带参数的 Block
int (^addBlock)(int, int) = ^(int a, int b) {
return a + b;
};
int result = addBlock(5, 3); // 8
// 带返回类型的 Block
NSString *(^greetBlock)(NSString *) = ^NSString *(NSString *name) {
return [NSString stringWithFormat:@"Hello, %@", name];
};
NSString *greeting = greetBlock(@"Alice");
// Blocks 作为方法参数
- (void)fetchDataWithCompletion:
(void (^)(NSData *data, NSError *error))completion {
dispatch_async(dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 模拟网络调用
NSData *data = [@"response" dataUsingEncoding:NSUTF8StringEncoding];
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) {
completion(data, nil);
}
});
});
}
// 使用基于 Block 的 API
- (void)loadData {
[self fetchDataWithCompletion:^(NSData *data, NSError *error) {
if (error) {
NSLog(@"Error: %@", error);
} else {
NSLog(@"Data: %@", data);
}
}];
}
// Block 类型的 Typedef
typedef void (^CompletionBlock)(BOOL success);
typedef void (^DataBlock)(NSData *data, NSError *error);
typedef NSString *(^TransformBlock)(NSString *input);
- (void)performOperationWithCompletion:(CompletionBlock)completion {
// 异步操作
dispatch_async(dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 工作
BOOL success = YES;
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) {
completion(success);
}
});
});
}
// 集合中的 Blocks
NSArray *blocks = @[
^{ NSLog(@"Block 1"); },
^{ NSLog(@"Block 2"); },
^{ NSLog(@"Block 3"); }
];
for (void (^block)(void) in blocks) {
block();
}
// Block 属性
@interface AsyncOperation : NSObject
@property (nonatomic, copy) CompletionBlock completion;
@property (nonatomic, copy) DataBlock dataHandler;
@end
@implementation AsyncOperation
@end
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
当将 Blocks 存储在属性或集合中时,必须进行复制以将其从栈移动到堆存储。
Blocks 从其定义作用域捕获变量,对于不同的存储类型和限定符有不同的行为。
// 捕获局部变量
void captureExample(void) {
NSInteger x = 10;
void (^block)(void) = ^{
NSLog(@"x = %ld", (long)x); // 捕获 x 的值
};
x = 20;
block(); // 打印 "x = 10" (在 Block 创建时捕获)
}
// __block 限定符用于可变捕获
void mutableCaptureExample(void) {
__block NSInteger counter = 0;
void (^incrementBlock)(void) = ^{
counter++; // 可以修改 counter
};
incrementBlock();
incrementBlock();
NSLog(@"Counter: %ld", (long)counter); // 2
}
// 在方法中捕获 self
@interface Counter : NSObject
@property (nonatomic, assign) NSInteger count;
- (void)incrementAsync;
@end
@implementation Counter
- (void)incrementAsync {
// 强引用捕获 self
dispatch_async(dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
self.count++; // 强引用捕获 self
});
}
@end
// 针对 self 的弱-强舞
@interface ViewController : UIViewController
@property (nonatomic, strong) NSTimer *timer;
@end
@implementation ViewController
- (void)startTimer {
__weak typeof(self) weakSelf = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0
repeats:YES
block:^(NSTimer *timer) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) return;
// 安全使用 strongSelf
[strongSelf updateUI];
}];
}
- (void)updateUI {
NSLog(@"Updating UI");
}
- (void)dealloc {
[self.timer invalidate];
}
@end
// 捕获对象与基本类型
void objectCaptureExample(void) {
NSMutableString *string = [NSMutableString stringWithString:@"Hello"];
void (^block)(void) = ^{
[string appendString:@" World"]; // 可以改变对象
NSLog(@"%@", string);
};
block(); // 打印 "Hello World"
}
// Block 循环引用
@interface NetworkManager : NSObject
@property (nonatomic, copy) void (^completion)(NSData *data);
@end
@implementation NetworkManager
- (void)fetchData {
__weak typeof(self) weakSelf = self;
self.completion = ^(NSData *data) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) return;
[strongSelf processData:data];
};
}
- (void)processData:(NSData *)data {
NSLog(@"Processing: %@", data);
}
@end
// 捕获 __block 对象
void blockObjectExample(void) {
__block NSMutableArray *array = [NSMutableArray array];
void (^addBlock)(id) = ^(id object) {
[array addObject:object]; // 可以改变和重新赋值
};
addBlock(@"Item 1");
addBlock(@"Item 2");
array = [NSMutableArray array]; // 可以重新赋值
}
捕获 self 时使用 __weak 来避免循环引用,使用 __block 来允许修改捕获的变量。
GCD 使用调度队列来管理并发执行,串行队列顺序执行任务,并发队列并行执行任务。
// 主队列 (串行,主线程)
dispatch_async(dispatch_get_main_queue(), ^{
// 更新 UI
NSLog(@"On main thread");
});
// 全局并发队列
dispatch_queue_t highPriorityQueue = dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_queue_t defaultQueue = dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t lowPriorityQueue = dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_LOW, 0);
dispatch_queue_t backgroundQueue = dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
// 在全局队列上异步执行
dispatch_async(defaultQueue, ^{
// 后台工作
NSLog(@"Background work");
dispatch_async(dispatch_get_main_queue(), ^{
// 在主队列上更新 UI
NSLog(@"UI update");
});
});
// 自定义串行队列
dispatch_queue_t serialQueue = dispatch_queue_create("com.example.serial", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{
NSLog(@"Task 1");
});
dispatch_async(serialQueue, ^{
NSLog(@"Task 2");
});
// 自定义并发队列
dispatch_queue_t concurrentQueue = dispatch_queue_create(
"com.example.concurrent", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(concurrentQueue, ^{
NSLog(@"Concurrent task 1");
});
dispatch_async(concurrentQueue, ^{
NSLog(@"Concurrent task 2");
});
// 同步调度 (阻塞直到完成)
__block NSString *result;
dispatch_sync(serialQueue, ^{
result = @"Computed value";
});
NSLog(@"Result: %@", result);
// 延迟调度 (延迟执行)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC),
dispatch_get_main_queue(), ^{
NSLog(@"Executed after 2 seconds");
});
// 单次调度 (线程安全的单例)
+ (instancetype)sharedInstance {
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
// 服务质量 (iOS 8+)
dispatch_queue_t userInitiatedQueue = dispatch_get_global_queue(
QOS_CLASS_USER_INITIATED, 0);
dispatch_queue_t utilityQueue = dispatch_get_global_queue(QOS_CLASS_UTILITY, 0);
dispatch_async(userInitiatedQueue, ^{
// 用户发起的工作 (高优先级)
});
使用主队列进行 UI 更新,全局队列进行后台工作,自定义队列用于同步和有序执行。
调度组协调多个异步操作,在所有任务完成时发出通知。
// 基本调度组
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_async(group, queue, ^{
NSLog(@"Task 1");
});
dispatch_group_async(group, queue, ^{
NSLog(@"Task 2");
});
dispatch_group_async(group, queue, ^{
NSLog(@"Task 3");
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"All tasks complete");
});
// 等待组完成
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"After wait");
// 手动 enter/leave
dispatch_group_t manualGroup = dispatch_group_create();
dispatch_group_enter(manualGroup);
[self fetchDataWithCompletion:^(NSData *data, NSError *error) {
NSLog(@"Data fetched");
dispatch_group_leave(manualGroup);
}];
dispatch_group_enter(manualGroup);
[self fetchImageWithCompletion:^(UIImage *image, NSError *error) {
NSLog(@"Image fetched");
dispatch_group_leave(manualGroup);
}];
dispatch_group_notify(manualGroup, dispatch_get_main_queue(), ^{
NSLog(@"All fetches complete");
});
// 实际示例:加载多个资源
- (void)loadAllResources {
dispatch_group_t resourceGroup = dispatch_group_create();
__block NSData *userData = nil;
__block NSData *settingsData = nil;
__block UIImage *profileImage = nil;
dispatch_group_enter(resourceGroup);
[self fetchUserDataWithCompletion:^(NSData *data) {
userData = data;
dispatch_group_leave(resourceGroup);
}];
dispatch_group_enter(resourceGroup);
[self fetchSettingsWithCompletion:^(NSData *data) {
settingsData = data;
dispatch_group_leave(resourceGroup);
}];
dispatch_group_enter(resourceGroup);
[self fetchProfileImageWithCompletion:^(UIImage *image) {
profileImage = image;
dispatch_group_leave(resourceGroup);
}];
dispatch_group_notify(resourceGroup, dispatch_get_main_queue(), ^{
// 所有资源已加载
[self updateUIWithUser:userData settings:settingsData image:profileImage];
});
}
- (void)fetchUserDataWithCompletion:(void (^)(NSData *))completion {
dispatch_async(dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if (completion) completion([NSData data]);
});
}
- (void)fetchSettingsWithCompletion:(void (^)(NSData *))completion {
dispatch_async(dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if (completion) completion([NSData data]);
});
}
- (void)fetchProfileImageWithCompletion:(void (^)(UIImage *))completion {
dispatch_async(dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if (completion) completion([[UIImage alloc] init]);
});
}
- (void)updateUIWithUser:(NSData *)user settings:(NSData *)settings
image:(UIImage *)image {
NSLog(@"Updating UI with all resources");
}
调度组对于协调多个异步操作并确保所有操作在继续之前完成至关重要。
屏障为并发队列中的共享资源提供同步访问。
// 用于读写模式的调度屏障
@interface ThreadSafeCache : NSObject
@property (nonatomic, strong) dispatch_queue_t concurrentQueue;
@property (nonatomic, strong) NSMutableDictionary *cache;
@end
@implementation ThreadSafeCache
- (instancetype)init {
self = [super init];
if (self) {
self.concurrentQueue = dispatch_queue_create(
"com.example.cache",
DISPATCH_QUEUE_CONCURRENT
);
self.cache = [NSMutableDictionary dictionary];
}
return self;
}
// 允许多个读取者
- (id)objectForKey:(NSString *)key {
__block id object;
dispatch_sync(self.concurrentQueue, ^{
object = self.cache[key];
});
return object;
}
// 使用屏障进行独占写入
- (void)setObject:(id)object forKey:(NSString *)key {
dispatch_barrier_async(self.concurrentQueue, ^{
self.cache[key] = object;
});
}
// 同步屏障写入
- (void)setObjectSync:(id)object forKey:(NSString *)key {
dispatch_barrier_sync(self.concurrentQueue, ^{
self.cache[key] = object;
});
}
@end
// 使用信号量限制并发
- (void)downloadImagesWithLimit:(NSArray<NSURL *> *)urls {
dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);
// 最大 3 个并发
dispatch_queue_t queue = dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (NSURL *url in urls) {
dispatch_async(queue, ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// 下载图片
NSLog(@"Downloading: %@", url);
[NSThread sleepForTimeInterval:1.0]; // 模拟下载
dispatch_semaphore_signal(semaphore);
});
}
}
// 使用 dispatch apply 进行并行循环
- (void)processItems:(NSArray *)items {
dispatch_apply(items.count, dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index) {
id item = items[index];
NSLog(@"Processing item %zu: %@", index, item);
// 并行处理项目
});
}
// 使用 dispatch_sync 的互斥锁替代方案
@interface Counter2 : NSObject
@property (nonatomic, strong) dispatch_queue_t syncQueue;
@property (nonatomic, assign) NSInteger count;
@end
@implementation Counter2
- (instancetype)init {
self = [super init];
if (self) {
self.syncQueue = dispatch_queue_create("com.example.counter", DISPATCH_QUEUE_SERIAL);
self.count = 0;
}
return self;
}
- (void)increment {
dispatch_sync(self.syncQueue, ^{
self.count++;
});
}
- (NSInteger)currentCount {
__block NSInteger value;
dispatch_sync(self.syncQueue, ^{
value = self.count;
});
return value;
}
@end
屏障确保独占写入访问,同时允许并发读取,是线程安全缓存和数据结构的理想选择。
现代 Cocoa API 广泛使用 Blocks 进行回调,为委托模式提供了更简洁的替代方案。
// 使用 Blocks 的 NSURLSession
- (void)fetchURL:(NSURL *)url {
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response,
NSError *error) {
if (error) {
NSLog(@"Error: %@", error);
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
// 在主线程处理数据
NSLog(@"Data received: %@", data);
});
}];
[task resume];
}
// 使用 Blocks 的 UIView 动画
- (void)animateView:(UIView *)view {
[UIView animateWithDuration:0.3
animations:^{
view.alpha = 0.0;
view.transform = CGAffineTransformMakeScale(0.5, 0.5);
} completion:^(BOOL finished) {
if (finished) {
[view removeFromSuperview];
}
}];
}
// 使用 Blocks 的 NSNotificationCenter
- (void)observeNotifications {
id observer = [[NSNotificationCenter defaultCenter]
addObserverForName:UIApplicationDidEnterBackgroundNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
NSLog(@"App entered background");
}];
// 存储观察者以便稍后移除
}
// 自定义基于 Block 的 API
typedef void (^ProgressBlock)(CGFloat progress);
typedef void (^CompletionBlock2)(BOOL success, NSError *error);
@interface Downloader : NSObject
- (void)downloadFile:(NSURL *)url
progress:(ProgressBlock)progress
completion:(CompletionBlock2)completion;
@end
@implementation Downloader
- (void)downloadFile:(NSURL *)url
progress:(ProgressBlock)progress
completion:(CompletionBlock2)completion {
dispatch_async(dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 模拟带进度的下载
for (NSInteger i = 0; i <= 100; i += 10) {
[NSThread sleepForTimeInterval:0.1];
dispatch_async(dispatch_get_main_queue(), ^{
if (progress) {
progress(i / 100.0);
}
});
}
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) {
completion(YES, nil);
}
});
});
}
@end
// 使用自定义 Block API
- (void)downloadExample {
Downloader *downloader = [[Downloader alloc] init];
NSURL *url = [NSURL URLWithString:@"https://example.com/file.zip"];
[downloader downloadFile:url
progress:^(CGFloat progress) {
NSLog(@"Progress: %.0f%%", progress * 100);
} completion:^(BOOL success, NSError *error) {
if (success) {
NSLog(@"Download complete");
} else {
NSLog(@"Download failed: %@", error);
}
}];
}
基于 Block 的 API 提供了内联回调处理,无需委托或通知观察者的样板代码。
将 Blocks 存储在属性中时进行复制,以将其从栈移动到堆,并防止悬垂指针导致的崩溃。
在作为属性存储的 Blocks 中使用弱-强舞捕获 self,以打破循环引用。
使用 dispatch_async 将 UI 更新调度到主队列,以确保线程安全的 UI 修改。
优先使用调度组而非嵌套回调,以清晰地协调多个异步操作。
在读写模式中使用调度屏障,以允许并发读取同时确保独占写入。
为同步创建自定义队列,而不是使用全局队列,以避免争用和优先级问题。
在调用 Blocks 前检查是否为 nil,以防止因未实现的可选 Block 参数而崩溃。
使用 dispatch_once 实现线程安全的单例,以确保无需锁即可进行一次性初始化。
使用信号量限制并发,当访问网络连接等速率受限的资源时。
使用 Instruments 进行性能分析,以识别队列争用、线程爆炸和性能瓶颈。
在作为属性存储的 Blocks 中强引用捕获 self 会导致内存泄漏。
存储 Blocks 时不进行复制,当栈分配的 Blocks 超出作用域时会导致崩溃。
在当前队列上使用 dispatch_sync 会导致死锁;永远不要同步调度到你所在的队列。
忘记将 UI 更新调度到主队列 会导致崩溃或未定义行为。
过度使用 dispatch_sync 会不必要地阻塞线程;为了更好的性能,优先使用异步调度。
dispatch_group_enter/leave 不平衡 会导致组通知永不触发或过早触发。
从多个队列访问可变状态而不进行同步 会导致竞态条件和数据损坏。
创建过多的自定义队列 会浪费资源;在适当的地方重用队列。
在全局队列上使用屏障 无效,因为屏障需要自定义并发队列。
在弱-强舞中不加 nil 检查就阻塞,如果 weakSelf 在执行过程中变为 nil,会导致崩溃。
在构建需要异步操作、并发处理或基于回调的 API 的 iOS、macOS、watchOS 或 tvOS 应用程序时,使用 Blocks 和 GCD。
将调度队列用于后台处理、网络调用、文件 I/O 或任何不应阻塞主线程的操作。
当协调多个必须在继续之前全部完成的异步操作时(例如加载多个资源),使用调度组。
对于支持并发读取和独占写入的线程安全数据结构,利用调度屏障。
在设计提供内联回调处理而无需委托样板代码的现代 Objective-C 接口时,使用基于 Block 的 API。
每周安装次数
–
代码仓库
GitHub 星标数
122
首次出现
–
安全审计
Blocks are Objective-C's closure implementation, providing anonymous functions that capture surrounding context. Grand Central Dispatch (GCD) is Apple's low-level API for managing concurrent operations using dispatch queues rather than threads directly.
Blocks enable functional programming patterns, callbacks, and clean asynchronous API design. GCD simplifies concurrency by abstracting thread management into queues that automatically distribute work across available CPU cores. Together, they form the foundation for modern Objective-C concurrent programming.
This skill covers block syntax and semantics, capture behavior, GCD queues and dispatch functions, synchronization primitives, and patterns for safe concurrent code.
Blocks are first-class objects that encapsulate code and can capture variables from their defining scope.
// Basic block syntax
void (^simpleBlock)(void) = ^{
NSLog(@"Hello from block");
};
simpleBlock(); // Call block
// Block with parameters
int (^addBlock)(int, int) = ^(int a, int b) {
return a + b;
};
int result = addBlock(5, 3); // 8
// Block with return type
NSString *(^greetBlock)(NSString *) = ^NSString *(NSString *name) {
return [NSString stringWithFormat:@"Hello, %@", name];
};
NSString *greeting = greetBlock(@"Alice");
// Blocks as method parameters
- (void)fetchDataWithCompletion:
(void (^)(NSData *data, NSError *error))completion {
dispatch_async(dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Simulate network call
NSData *data = [@"response" dataUsingEncoding:NSUTF8StringEncoding];
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) {
completion(data, nil);
}
});
});
}
// Using block-based API
- (void)loadData {
[self fetchDataWithCompletion:^(NSData *data, NSError *error) {
if (error) {
NSLog(@"Error: %@", error);
} else {
NSLog(@"Data: %@", data);
}
}];
}
// Typedef for block types
typedef void (^CompletionBlock)(BOOL success);
typedef void (^DataBlock)(NSData *data, NSError *error);
typedef NSString *(^TransformBlock)(NSString *input);
- (void)performOperationWithCompletion:(CompletionBlock)completion {
// Async operation
dispatch_async(dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Work
BOOL success = YES;
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) {
completion(success);
}
});
});
}
// Blocks in collections
NSArray *blocks = @[
^{ NSLog(@"Block 1"); },
^{ NSLog(@"Block 2"); },
^{ NSLog(@"Block 3"); }
];
for (void (^block)(void) in blocks) {
block();
}
// Block properties
@interface AsyncOperation : NSObject
@property (nonatomic, copy) CompletionBlock completion;
@property (nonatomic, copy) DataBlock dataHandler;
@end
@implementation AsyncOperation
@end
Blocks must be copied when stored in properties or collections to move them from stack to heap storage.
Blocks capture variables from their defining scope, with different behaviors for different storage types and qualifiers.
// Capturing local variables
void captureExample(void) {
NSInteger x = 10;
void (^block)(void) = ^{
NSLog(@"x = %ld", (long)x); // Captures value of x
};
x = 20;
block(); // Prints "x = 10" (captured at block creation)
}
// __block qualifier for mutable capture
void mutableCaptureExample(void) {
__block NSInteger counter = 0;
void (^incrementBlock)(void) = ^{
counter++; // Can modify counter
};
incrementBlock();
incrementBlock();
NSLog(@"Counter: %ld", (long)counter); // 2
}
// Capturing self in methods
@interface Counter : NSObject
@property (nonatomic, assign) NSInteger count;
- (void)incrementAsync;
@end
@implementation Counter
- (void)incrementAsync {
// Strong capture of self
dispatch_async(dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
self.count++; // Captures self strongly
});
}
@end
// Weak-strong dance for self
@interface ViewController : UIViewController
@property (nonatomic, strong) NSTimer *timer;
@end
@implementation ViewController
- (void)startTimer {
__weak typeof(self) weakSelf = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0
repeats:YES
block:^(NSTimer *timer) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) return;
// Safe to use strongSelf
[strongSelf updateUI];
}];
}
- (void)updateUI {
NSLog(@"Updating UI");
}
- (void)dealloc {
[self.timer invalidate];
}
@end
// Capturing objects vs primitives
void objectCaptureExample(void) {
NSMutableString *string = [NSMutableString stringWithString:@"Hello"];
void (^block)(void) = ^{
[string appendString:@" World"]; // Can mutate object
NSLog(@"%@", string);
};
block(); // Prints "Hello World"
}
// Block retain cycles
@interface NetworkManager : NSObject
@property (nonatomic, copy) void (^completion)(NSData *data);
@end
@implementation NetworkManager
- (void)fetchData {
__weak typeof(self) weakSelf = self;
self.completion = ^(NSData *data) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) return;
[strongSelf processData:data];
};
}
- (void)processData:(NSData *)data {
NSLog(@"Processing: %@", data);
}
@end
// Capturing __block objects
void blockObjectExample(void) {
__block NSMutableArray *array = [NSMutableArray array];
void (^addBlock)(id) = ^(id object) {
[array addObject:object]; // Can mutate and reassign
};
addBlock(@"Item 1");
addBlock(@"Item 2");
array = [NSMutableArray array]; // Can reassign
}
Use __weak to avoid retain cycles when capturing self, and __block to allow mutation of captured variables.
GCD uses dispatch queues to manage concurrent execution, with serial queues executing tasks sequentially and concurrent queues executing them in parallel.
// Main queue (serial, main thread)
dispatch_async(dispatch_get_main_queue(), ^{
// Update UI
NSLog(@"On main thread");
});
// Global concurrent queues
dispatch_queue_t highPriorityQueue = dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_queue_t defaultQueue = dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t lowPriorityQueue = dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_LOW, 0);
dispatch_queue_t backgroundQueue = dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
// Async execution on global queue
dispatch_async(defaultQueue, ^{
// Background work
NSLog(@"Background work");
dispatch_async(dispatch_get_main_queue(), ^{
// Update UI on main queue
NSLog(@"UI update");
});
});
// Custom serial queue
dispatch_queue_t serialQueue = dispatch_queue_create("com.example.serial", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{
NSLog(@"Task 1");
});
dispatch_async(serialQueue, ^{
NSLog(@"Task 2");
});
// Custom concurrent queue
dispatch_queue_t concurrentQueue = dispatch_queue_create(
"com.example.concurrent", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(concurrentQueue, ^{
NSLog(@"Concurrent task 1");
});
dispatch_async(concurrentQueue, ^{
NSLog(@"Concurrent task 2");
});
// Synchronous dispatch (blocks until complete)
__block NSString *result;
dispatch_sync(serialQueue, ^{
result = @"Computed value";
});
NSLog(@"Result: %@", result);
// Dispatch after (delayed execution)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC),
dispatch_get_main_queue(), ^{
NSLog(@"Executed after 2 seconds");
});
// Dispatch once (thread-safe singleton)
+ (instancetype)sharedInstance {
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
// Quality of service (iOS 8+)
dispatch_queue_t userInitiatedQueue = dispatch_get_global_queue(
QOS_CLASS_USER_INITIATED, 0);
dispatch_queue_t utilityQueue = dispatch_get_global_queue(QOS_CLASS_UTILITY, 0);
dispatch_async(userInitiatedQueue, ^{
// User-initiated work (high priority)
});
Use main queue for UI updates, global queues for background work, and custom queues for synchronization and ordered execution.
Dispatch groups coordinate multiple async operations, notifying when all tasks complete.
// Basic dispatch group
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_async(group, queue, ^{
NSLog(@"Task 1");
});
dispatch_group_async(group, queue, ^{
NSLog(@"Task 2");
});
dispatch_group_async(group, queue, ^{
NSLog(@"Task 3");
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"All tasks complete");
});
// Waiting for group completion
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"After wait");
// Manual enter/leave
dispatch_group_t manualGroup = dispatch_group_create();
dispatch_group_enter(manualGroup);
[self fetchDataWithCompletion:^(NSData *data, NSError *error) {
NSLog(@"Data fetched");
dispatch_group_leave(manualGroup);
}];
dispatch_group_enter(manualGroup);
[self fetchImageWithCompletion:^(UIImage *image, NSError *error) {
NSLog(@"Image fetched");
dispatch_group_leave(manualGroup);
}];
dispatch_group_notify(manualGroup, dispatch_get_main_queue(), ^{
NSLog(@"All fetches complete");
});
// Practical example: loading multiple resources
- (void)loadAllResources {
dispatch_group_t resourceGroup = dispatch_group_create();
__block NSData *userData = nil;
__block NSData *settingsData = nil;
__block UIImage *profileImage = nil;
dispatch_group_enter(resourceGroup);
[self fetchUserDataWithCompletion:^(NSData *data) {
userData = data;
dispatch_group_leave(resourceGroup);
}];
dispatch_group_enter(resourceGroup);
[self fetchSettingsWithCompletion:^(NSData *data) {
settingsData = data;
dispatch_group_leave(resourceGroup);
}];
dispatch_group_enter(resourceGroup);
[self fetchProfileImageWithCompletion:^(UIImage *image) {
profileImage = image;
dispatch_group_leave(resourceGroup);
}];
dispatch_group_notify(resourceGroup, dispatch_get_main_queue(), ^{
// All resources loaded
[self updateUIWithUser:userData settings:settingsData image:profileImage];
});
}
- (void)fetchUserDataWithCompletion:(void (^)(NSData *))completion {
dispatch_async(dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if (completion) completion([NSData data]);
});
}
- (void)fetchSettingsWithCompletion:(void (^)(NSData *))completion {
dispatch_async(dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if (completion) completion([NSData data]);
});
}
- (void)fetchProfileImageWithCompletion:(void (^)(UIImage *))completion {
dispatch_async(dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if (completion) completion([[UIImage alloc] init]);
});
}
- (void)updateUIWithUser:(NSData *)user settings:(NSData *)settings
image:(UIImage *)image {
NSLog(@"Updating UI with all resources");
}
Dispatch groups are essential for coordinating multiple async operations and ensuring all complete before proceeding.
Barriers provide synchronized access to shared resources in concurrent queues.
// Dispatch barrier for reader-writer pattern
@interface ThreadSafeCache : NSObject
@property (nonatomic, strong) dispatch_queue_t concurrentQueue;
@property (nonatomic, strong) NSMutableDictionary *cache;
@end
@implementation ThreadSafeCache
- (instancetype)init {
self = [super init];
if (self) {
self.concurrentQueue = dispatch_queue_create(
"com.example.cache",
DISPATCH_QUEUE_CONCURRENT
);
self.cache = [NSMutableDictionary dictionary];
}
return self;
}
// Multiple readers allowed
- (id)objectForKey:(NSString *)key {
__block id object;
dispatch_sync(self.concurrentQueue, ^{
object = self.cache[key];
});
return object;
}
// Exclusive writer with barrier
- (void)setObject:(id)object forKey:(NSString *)key {
dispatch_barrier_async(self.concurrentQueue, ^{
self.cache[key] = object;
});
}
// Synchronous barrier write
- (void)setObjectSync:(id)object forKey:(NSString *)key {
dispatch_barrier_sync(self.concurrentQueue, ^{
self.cache[key] = object;
});
}
@end
// Semaphores for limiting concurrency
- (void)downloadImagesWithLimit:(NSArray<NSURL *> *)urls {
dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);
// Max 3 concurrent
dispatch_queue_t queue = dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (NSURL *url in urls) {
dispatch_async(queue, ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// Download image
NSLog(@"Downloading: %@", url);
[NSThread sleepForTimeInterval:1.0]; // Simulate download
dispatch_semaphore_signal(semaphore);
});
}
}
// Dispatch apply for parallel loops
- (void)processItems:(NSArray *)items {
dispatch_apply(items.count, dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index) {
id item = items[index];
NSLog(@"Processing item %zu: %@", index, item);
// Process item in parallel
});
}
// Mutex alternative with dispatch_sync
@interface Counter2 : NSObject
@property (nonatomic, strong) dispatch_queue_t syncQueue;
@property (nonatomic, assign) NSInteger count;
@end
@implementation Counter2
- (instancetype)init {
self = [super init];
if (self) {
self.syncQueue = dispatch_queue_create("com.example.counter", DISPATCH_QUEUE_SERIAL);
self.count = 0;
}
return self;
}
- (void)increment {
dispatch_sync(self.syncQueue, ^{
self.count++;
});
}
- (NSInteger)currentCount {
__block NSInteger value;
dispatch_sync(self.syncQueue, ^{
value = self.count;
});
return value;
}
@end
Barriers ensure exclusive write access while allowing concurrent reads, ideal for thread-safe caches and data structures.
Modern Cocoa APIs extensively use blocks for callbacks, providing cleaner alternatives to delegate patterns.
// NSURLSession with blocks
- (void)fetchURL:(NSURL *)url {
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response,
NSError *error) {
if (error) {
NSLog(@"Error: %@", error);
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
// Process data on main thread
NSLog(@"Data received: %@", data);
});
}];
[task resume];
}
// UIView animations with blocks
- (void)animateView:(UIView *)view {
[UIView animateWithDuration:0.3
animations:^{
view.alpha = 0.0;
view.transform = CGAffineTransformMakeScale(0.5, 0.5);
} completion:^(BOOL finished) {
if (finished) {
[view removeFromSuperview];
}
}];
}
// NSNotificationCenter with blocks
- (void)observeNotifications {
id observer = [[NSNotificationCenter defaultCenter]
addObserverForName:UIApplicationDidEnterBackgroundNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
NSLog(@"App entered background");
}];
// Store observer to remove later
}
// Custom block-based API
typedef void (^ProgressBlock)(CGFloat progress);
typedef void (^CompletionBlock2)(BOOL success, NSError *error);
@interface Downloader : NSObject
- (void)downloadFile:(NSURL *)url
progress:(ProgressBlock)progress
completion:(CompletionBlock2)completion;
@end
@implementation Downloader
- (void)downloadFile:(NSURL *)url
progress:(ProgressBlock)progress
completion:(CompletionBlock2)completion {
dispatch_async(dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Simulate download with progress
for (NSInteger i = 0; i <= 100; i += 10) {
[NSThread sleepForTimeInterval:0.1];
dispatch_async(dispatch_get_main_queue(), ^{
if (progress) {
progress(i / 100.0);
}
});
}
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) {
completion(YES, nil);
}
});
});
}
@end
// Using custom block API
- (void)downloadExample {
Downloader *downloader = [[Downloader alloc] init];
NSURL *url = [NSURL URLWithString:@"https://example.com/file.zip"];
[downloader downloadFile:url
progress:^(CGFloat progress) {
NSLog(@"Progress: %.0f%%", progress * 100);
} completion:^(BOOL success, NSError *error) {
if (success) {
NSLog(@"Download complete");
} else {
NSLog(@"Download failed: %@", error);
}
}];
}
Block-based APIs provide inline callback handling without the boilerplate of delegation or notification observers.
Copy blocks when storing in properties to move them from stack to heap and prevent crashes from dangling pointers
Use weak-strong dance for self capture in blocks stored as properties to break retain cycles
Dispatch UI updates to main queue using dispatch_async to ensure thread-safe UI modifications
Prefer dispatch groups over nested callbacks to coordinate multiple async operations cleanly
Use dispatch barriers for reader-writer patterns to allow concurrent reads while ensuring exclusive writes
Create custom queues for synchronization rather than using global queues to avoid contention and priority issues
Check for nil before calling blocks to prevent crashes from unimplemented optional block parameters
Use dispatch_once for thread-safe singletons to ensure exactly-once initialization without locks
Limit concurrency with semaphores when accessing rate-limited resources like network connections
Profile with Instruments to identify queue contention, thread explosion, and performance bottlenecks
Creating retain cycles with strong self capture in blocks stored as properties causes memory leaks
Not copying blocks when storing them leads to crashes when stack-allocated blocks go out of scope
Using dispatch_sync on current queue causes deadlock; never sync dispatch to the queue you're on
Forgetting to dispatch to main queue for UI updates causes crashes or undefined behavior
Overusing dispatch_sync blocks threads unnecessarily; prefer async dispatch for better performance
Not balancing dispatch_group_enter/leave causes group notifications to never fire or fire prematurely
Accessing mutable state without synchronization from multiple queues causes race conditions and data corruption
Creating too many custom queues wastes resources; reuse queues where appropriate
Using global queues for barriers doesn't work as barriers require custom concurrent queues
Blocking in weak-strong dance without nil check can cause crashes if weakSelf becomes nil during execution
Use blocks and GCD when building iOS, macOS, watchOS, or tvOS applications that require asynchronous operations, concurrent processing, or callback-based APIs.
Apply dispatch queues for background processing, network calls, file I/O, or any operation that shouldn't block the main thread.
Employ dispatch groups when coordinating multiple async operations that must all complete before proceeding, like loading multiple resources.
Leverage dispatch barriers for thread-safe data structures that support concurrent reads and exclusive writes.
Use block-based APIs when designing modern Objective-C interfaces that provide inline callback handling without delegate boilerplate.
Weekly Installs
–
Repository
GitHub Stars
122
First Seen
–
Security Audits
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
109,600 周安装