【问题标题】:Multithreaded iPhone app crashes with [NSAutoreleasePool release]多线程 iPhone 应用程序因 [NSAutoreleasePool 版本] 而崩溃
【发布时间】:2010-11-14 11:55:33
【问题描述】:

我在多线程 iPhone 应用程序中有一个与内存管理相关的问题。 假设我们有这个方法,它在与主 UI 线程不同的线程中调用:

- (BOOL)fetchAtIndex:(NSUInteger)index
{
    NSURL *theURL = [NSURL URLWithString:[queryURLs objectAtIndex:index]];
    // Pay attention to this line:
    NSData *theData = [[NetworkHelper fetchFromNetwork:theURL] retain];

    // Some code here...

    // Now what should I do before returning result?
    //[theData release]; ??
    //[theData autorelease]; ??
    return YES;
}

如您所见,我保留了从网络操作返回的NSData。问题是:为什么我不应该在方法结束时释放(或自动释放)它? 我让它工作的唯一方法是首先使用retain,然后什么都没有。如果我使用任何其他组合(什么都不用;retain 然后releaseautorelease),当我释放线程的NSAutoreleasePool 时,我的程序会因EXC_BAD_ACCESS 而崩溃。 我错过了什么?

仅供参考,这是线程的主要代码:

- (void)threadedDataFetching;
{
    // Create an autorelease pool for this thread
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    // Reload data in separate thread
    [self fetchAtIndex:0];

    // Signal the main thread that fetching is finished
    [self performSelectorOnMainThread:@selector(finishedFetchingAll) withObject:nil waitUntilDone:NO];

    // Release all objects in the autorelease pool
    [pool release]; // This line causes EXC_BAD_ACCESS
}

感谢您的帮助!

【问题讨论】:

    标签: iphone objective-c memory-management autorelease retain


    【解决方案1】:

    您不得发布您自己未保留的内容(使用retain 或通过带有initnewcopy 名义的方法暗示)。

    如果你保留来自fetchFromNetwork 的结果,那么你必须释放它。 releaseautorelease 都应该可以工作(不要在release 之后触摸对象,在release 之后将字段/变量设置为nil 是最安全的)。

    如果您不保留数据,那么您甚至不需要保留它。 [NetworkHelper fetchFromNetwork] 应该返回自动释放的对象。 fetchFromNetwork 的正文可能如下所示:

    NSData *data = [[NSData alloc] init];
    // stuff happens
    return [data autorelease];
    

    NSData *data = [otherObject dataFromOtherObject];
    // stuff happens
    return data; // don't (auto)release, since you haven't retained
    

    如果有疑问,请在泄漏方面犯错并通过“泄漏”仪器或LLVM checker 运行应用程序。

    【讨论】:

    • 谢谢。实际上, fetchFromNetwork 就像您的第二个代码示例: NSData *data = [otherObject dataFromOtherObject]; ...返回[数据自动释放]; // 这里错了!这就是为什么我必须将它保留在我的客户端代码中。我删除了错误的 -autorelease 调用,然后是客户端的 -retain 代码,现在一切都很好。谢谢!
    【解决方案2】:

    您在单独的线程上的事实可能与此无关。内存管理是相同的,您应该平衡 NSData 的保留/释放,就好像这是主线程一样。您在排空自动释放池时崩溃的事实表明您可能已经对未在此处显示的数据进行了某些操作(这似乎很明显,因为显示的代码不是很有用)。您对需要其他人保留的数据做了什么?

    【讨论】:

    • 你说得对,正如我在另一条评论中所写,fetchFromNetwork 正在自动释放 NSData 对象,所以我不得不将它保留在这段代码中,这样它就可以工作了,但是有问题部分在 fetchFromNetwork 方法中。谢谢。
    【解决方案3】:

    正如其他人所指出的,在这种情况下它实际上是多线程的并不相关。 Apple 生产的 Objective C Memory Management Guidelines 值得一读。

    粗略地说,任何你自己显式地 [[Foo alloc] init] 的对象,你都应该负责清理。如果你从一个方法中返回这个值,你也需要自动释放它。

    您从调用者那里获得的任何对象不是以 initWith 开头的(例如 [Foo emptyFoo]),调用者有责任拥有资源(即自动释放它)。

    如果您传递了一个对象并希望将其保留在方法调用之外(即将其保存到实例字段),则必须保留它。完成后,通常在析构函数中释放它。如果您使用的是 Objective C 属性,将其定义为 @retain 将自动为您启动此行为;在析构函数中,您可以将属性设置为 nil。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-07
      • 1970-01-01
      • 2015-09-22
      • 1970-01-01
      • 2023-03-14
      相关资源
      最近更新 更多