WWDC 2010“Blocks and Grand Central Dispatch”演讲中提出的模式之一是使用嵌套的dispatch_async调用在后台线程上执行耗时的任务,然后在任务完成后更新主线程上的UI < / p>
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];
});
});
由于“myViewController”正在块中使用,它会自动获得“保留”,并在清除块时稍后获得“释放”。
如果块的'release'调用是最终的释放调用(例如,用户在后台任务运行时导航远离视图),则会调用myViewController dealloc方法 - 但它会在后台线程上调用!!
UIKit对象不喜欢在主线程之外取消分配。就我而言,UIWebView会抛出异常。
这个WWDC如何呈现模式 - 特别提到作为避免UI锁定的最佳新方法 - 是如此有缺陷?我错过了什么吗?
答案 0 :(得分:11)
对于这种情况,您可以使用__block
存储类型限定符。块不会自动保留__block
个变量。所以你需要自己保留对象:
__block UIViewController *viewController = [myViewController retain];
dispatch_async(backgroundQueue, ^{
// Do long-running work here.
dispatch_async(dispatch_get_main_queue(), ^{
[viewController updateUIWithResults:results];
[viewController release]; // Ensure it's released on main thread
}
});
修改强>
使用ARC,__block变量对象由块自动保留,但我们可以将_llock值设置为__block变量,以便随时释放保留的对象。
__block UIViewController *viewController = myViewController;
dispatch_async(backgroundQueue, ^{
// Do long-running work here.
dispatch_async(dispatch_get_main_queue(), ^{
[viewController updateUIWithResults:results];
viewController = nil; // Ensure it's released on main thread
}
});
答案 1 :(得分:2)
在一个帖子中,我只是在线程使用结束时使用[viewController retain];
[viewController release]
。它有效,我不使用GCD~
答案 2 :(得分:-2)
这对我有用(添加了一个计时器):
[self retain]; // this guarantees that the last release will be on the main threaad
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];
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(releaseMe:) userInfo:nil repeats:NO];
});
});
- (void)releaseMe:(NSTimer *)theTimer {
[self release]; // will be on the main thread
}