多线程 iPhone 应用程序因 [NSAutoreleasePool release] 崩溃

发布于 2024-07-27 23:37:53 字数 1344 浏览 8 评论 0原文

我在多线程 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),我的程序会崩溃并显示 EXC_BAD_ACCESS 当我释放线程的 NSAutoreleasePool 时。 我缺少什么?

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

- (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
}

感谢您的帮助!

I have a memory management-related question in a multithreaded iPhone application.
Let's say we have this method, that is called in a separate thread than the main-UI-thread:

- (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;
}

As you can see, I'm retaining the NSData I got back from my network operation. The question is: why shouldn't I release (or autorelease) it at the end of my method?
The only way I made it work is to use retain at first, and nothing then. If I use any other combination (nothing at all; retain then release or autorelease), my program crashes with EXC_BAD_ACCESS when I release the thread's NSAutoreleasePool.
What am I missing?

FYI, here is the main code for the thread:

- (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
}

Thanks for your help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

少钕鈤記 2024-08-03 23:37:54

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

The fact that you're on a separate thread is likely not relevant here. Memory management is the same, and you should be balancing your retain/release of NSData just as if this were the main thread. The fact that you're crashing when draining the autorelease pool suggests that you've probably done something with theData that you haven't showed us here (which seems obvious since the code as shown isn't very useful). What are you doing with theData that is requiring someone else to retain it?

仲春光 2024-08-03 23:37:54

正如其他人所指出的,在这种情况下,它是多线程的实际上并不相关。 值得一读的 Objective C 内存管理指南苹果生产。

粗略地说,任何您自己显式 [[Foo alloc] init] 的对象,您都应该承担清理的责任。 如果您从方法返回此值,则还需要自动释放它。

从调用者处获得的任何不以 initWith 开头的对象(例如 [FooemptyFoo]),调用者有责任拥有该资源(即自动释放它)。

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

As others have noted, it's not actually relevant that it's multithreaded in this instance. It's worth reading up on the Objective C Memory Management Guidelines that Apple produces.

Roughly speaking, any objects that you explicitly [[Foo alloc] init] yourself, you should own the responsibility for cleaning up. If you're returning this value from a method, you need to autorelease it as well.

Any object you get from a caller that doesn't begin with initWith (such as [Foo emptyFoo]) it's the responsibility of the caller to own the resource (i.e. autorelease it).

If you get passed an object and want to keep it outside of the method call (i.e. save it to an instance field) you must retain it. When you're done, you release it, usually in the destructor. If you're using Objective C properties, defining it as @retain will kick in this behaviour for you automatically; in the destructor, you can just set the property to nil.

不醒的梦 2024-08-03 23:37:53

您不得释放自己未保留的内容(使用 retain 或通过以下方法隐式释放:initnewcopy 以他们的名字命名)。

如果您保留 fetchFromNetwork 的结果,则必须释放它。 releaseautorelease 都应该可以工作(在 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

如果有疑问,请在泄漏方面犯错误并通过“Leaks”仪器或 LLVM 检查器

You must not release things you have not retained yourself (using either retain or implictly by methods with: init, new, or copy in their name).

If you retain result from fetchFromNetwork, then you must release it. Both release and autorelease should work (don't touch object after release, it's safest to set fields/variables to nil after release).

If you're not keeping the data, then you don't even need to retain it. [NetworkHelper fetchFromNetwork] should return autoreleased object. Body of fetchFromNetwork could look like this:

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

or

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

If in doubt, err on the leaky side and run application via "Leaks" Instruments or LLVM checker.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文