WWDC 2010"Blocks and Grand Central Dispatch"演讲中提出的模式之一是使用嵌套的dispatch_async调用在后台线程上执行耗时的任务,然后在任务完成后更新主线程上的UI
dispatch_async(backgroundQueue, ^{
// do something time consuming in background
NSArray *results = ComputeBigKnarlyThingThatWouldBlockForAWhile();
// use results on the main thread
dispatch_async(dispatch_get_main_queue(), ^{
[myViewController UpdateUiWithResults:results];
});
});
Run Code Online (Sandbox Code Playgroud)
由于"myViewController"正在块中使用,它会自动获得"保留",并在清除块时稍后获得"释放".
如果块的'release'调用是最终的释放调用(例如,用户在后台任务运行时导航远离视图),则调用myViewController dealloc方法 - 但是它在后台线程上调用!!
UIKit对象不喜欢在主线程之外取消分配.在我的例子中,UIWebView抛出异常.
这个WWDC如何呈现模式 - 特别提到避免UI锁定的最佳新方法 - 是如此有缺陷?我错过了什么吗?
我有一个视图控制器,可以在后台GCD队列中下载资产.我将下载函数传递给回调块,以便在下载完成后执行,并且它总是在主线程上执行此块.
如果我的视图控制器在下载完成之前被用户解雇,则会出现此问题.我怀疑发生了什么,一旦我的视图控制器被解除,回调块是唯一保留对控制器的强引用的东西.回调块仅保留在后台线程中,因此一旦释放,回调块范围内捕获的所有对象也将被释放,尽管在后台队列中.
这就是问题:在后台队列中释放会导致dealloc在同一队列中运行,而不是在主队列中运行.反过来,这会dealloc在后台调用,应用程序崩溃:
2012-01-19 12:47:36.349 500px iOS[4892:12107] bool _WebTryThreadLock(bool), 0x306c10: 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...
[Switching to process 16643 thread 0x4103]
[Switching to process 16643 thread 0x4103]
(gdb) where
#0 0x307fd3c8 in _WebTryThreadLock ()
#1 0x307ff1b0 in WebThreadLock ()
#2 0x33f7865e in -[UITextView dealloc] ()
#3 0x0005d2ce in -[GCPlaceholderTextView dealloc] …Run Code Online (Sandbox Code Playgroud) memory-management objective-c grand-central-dispatch ios automatic-ref-counting
从后台线程调用dealloca 是错误的UIViewController吗?似乎UITextView(可以?)最终调用_WebTryThreadLock哪个导致:
bool _WebTryThreadLock(bool):试图从主线程或Web线程以外的线程获取Web锁.这可能是从辅助线程调用UIKit的结果.
背景:我有一个子类NSOperation,它接受一个selector和一个target对象通知.
-(id)initWithTarget:(id)target {
if (self = [super init]) {
_target = [target retain];
}
return self;
}
-(void)dealloc {
[_target release];
[super dealloc];
}
Run Code Online (Sandbox Code Playgroud)
如果在UIViewController开始NSOperation运行时已经被解雇,那么调用将在后台线程上release触发它dealloc.