iPhone:在多线程环境中发布 UIViewController 时出现问题
Posted
技术标签:
【中文标题】iPhone:在多线程环境中发布 UIViewController 时出现问题【英文标题】:iPhone: Problems releasing UIViewController in a multithreaded environment 【发布时间】:2010-05-30 08:44:40 【问题描述】:我有一个 UIViewController,在该控制器中,我从 URL 源获取图像。图像在一个单独的线程中获取,然后在主线程上更新用户界面。此控制器显示为 UIScrollView 父级中的页面,该父级用于释放不再可见的控制器。
当线程在 UIViewController 释放之前完成获取内容时,一切正常 - 但是当用户在线程完成之前滚动到另一个页面时,控制器被释放并且控制器的唯一句柄由创建 releaseCount 的线程拥有控制器的值等于 1。现在,一旦线程耗尽 NSAutoreleasePool,控制器就会获得释放,因为 releaseCount 变为 0。此时,我的应用程序崩溃并且我收到以下错误消息:
bool _WebTryThreadLock(bool), 0x4d99c60: 试图从主线程或web线程以外的线程获取web lock。这可能是从辅助线程调用 UIKit 的结果。现在崩溃了...
回溯显示应用程序在调用 [super dealloc] 时崩溃了,这完全有道理,因为在池耗尽时线程必须触发 dealloc 函数。我的问题是,我怎样才能克服这个错误并在不泄漏内存的情况下释放控制器?
我尝试的一个解决方案是在池耗尽之前调用 [self retain] 以使 retainCount 不会降至零,然后使用以下代码在主线程中释放控制器:
[self performSelectorOnMainThread:@selector(autorelease)
withObject:nil waitUntilDone:NO];
不幸的是,这没有成功。下面是在线程上执行的函数:
- (void)thread_fetchContent
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSURL *imgURL = [NSURL URLWithString:@"http://www.domain.com/image.png"];
// UIImage *imgHotspot is declared as private - The image is retained
// here and released as soon as it is assigned to UIImageView
imgHotspot = [[[UIImage alloc] initWithData:
[NSData dataWithContentsOfURL: imgURL]] retain];
if ([self retainCount] == 1)
[self retain]; // increment retain count ~ workaround
[pool drain]; // drain pool
// this doesn't work - i get the same error
[self performSelectorOnMainThread:@selector(autorelease)
withObject:nil waitUntilDone:NO];
else
// show fetched image on the main thread - this works fine!
[self performSelectorOnMainThread:@selector(showImage)
withObject:nil waitUntilDone:NO];
[pool drain];
请帮忙!提前谢谢你。
【问题讨论】:
【参考方案1】:是的,尝试保持线程同步确实令人生畏。 您描述的用例听起来非常适合 NSOperation。 通过使用这种方法,您可以将 NSOperationQueue 作为控制器中的 ivar,并在控制器的 dealloc 方法中释放它。
好处很多,当控制器视图在滚动视图中可见时,它(viewWillAppear 或 loadView)开始使用添加到 NSOperationQueue 的 NSOperation 检索图像,如果用户在操作完成之前滚动并且 NSOperationQueue 是发布后,它将负责向所有操作发送取消消息,并通常以有序的方式关闭所有操作。
如果这是您的应用程序中的一个中心组件,我想这是因为您考虑释放“屏幕”的东西,我建议让您的控制器在 loadVIew 方法中显示“虚拟图像”,然后在 viewDidLoad 中启动 fetch 操作。您可以将 NSOperation 子类化,这样您只需将 URL 发送给它并让它完成它的工作。
几周前我做了类似的事情,我不得不不断地启动线程操作,但很有可能用户会做一些导致这些操作被取消的事情。该功能被“构建”到 NSOperation 中。 NSOperation question
【讨论】:
谢谢! NSOperation 方法很有帮助-我查看了您提供的链接和cimgf.com/2008/02/16/… 的教程-它解决了我的问题:)以上是关于iPhone:在多线程环境中发布 UIViewController 时出现问题的主要内容,如果未能解决你的问题,请参考以下文章