【发布时间】:2011-10-20 15:33:42
【问题描述】:
这个问题类似于this question 引入了自动引用计数。
我有一个NSOperation 子类,它接受一个块参数,该参数旨在作为主(UI)线程的回调。我的初衷是在后台进行一些操作,然后使用dispatch_async和主队列进行回调。
原前提:
@interface MySubclass : NSOperation {
@protected
dispatch_block_t _callback;
}
- (id)initWithCallback:(dispatch_block_t)callback;
@end
@implementation MySubclass
- (void)main
{
// Do stuff
if (![self isCancelled]) {
dispatch_async(dispatch_get_main_queue(), _callback);
}
}
@end
当所有对块范围之外的 UIKit 对象的引用都被删除时,就会出现问题。 (例如,UIViewController 从导航堆栈中弹出。)这留下了对块内对象的唯一引用,因此当块在释放块的线程上时,对象被释放,在释放块的线程上。从主线程中释放 UIKit 对象会使应用程序崩溃,并显示错误消息 Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...
作为一种解决方法,我在回调 ivar 中添加了一个 __block 修饰符,并使用 dispatch_sync 确保所有发布的内容都在主线程上。
@interface MySubclass : NSOperation {
@protected
__block dispatch_block_t _callback;
}
- (id)initWithCallback:(dispatch_block_t)callback;
@end
@implementation MySubclass
- (void)main
{
// Do Stuff
if (![self isCancelled]) {
dispatch_block_t block = ^{
_callback();
_callback = nil;
};
// Cover all our bases to prevent deadlock
if ([NSThread isMainThread]) block();
else dispatch_sync(dispatch_get_main_queue(), block);
}
}
@end
我想知道在这个前提下是否有更好的方法来完成某件事。我的解决方法感觉很老套,而且我不喜欢这样,我的队列中可能会有几个操作都在等待主线程打开,然后才能完成。
【问题讨论】:
-
顺便说一句,我遇到了你在代码末尾检查的类型的死锁,所以我现在在主线程上为 dispatch_sync 使用辅助函数:stackoverflow.com/questions/5225130/…
标签: objective-c ios grand-central-dispatch automatic-ref-counting