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 时出现问题的主要内容,如果未能解决你的问题,请参考以下文章

在多线程环境中使用 PyCurl 时程序消耗的内存不断增长

可以在多线程环境中使用单个 QueueConnection 吗?

如何在多线程环境中捕获 SIGABRT?

在多线程环境中使用 .Net UdpClient

在多线程环境中写入时的 Swift 数组复制

在多线程环境中更新 DataGrid 视图