多线程 iPhone 应用程序因 [NSAutoreleasePool release] 崩溃
我在多线程 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
然后 release
或 autorelease
),我的程序会崩溃并显示 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您位于单独线程上的事实可能与此无关。 内存管理是相同的,您应该平衡 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?
正如其他人所指出的,在这种情况下,它是多线程的实际上并不相关。 值得一读的 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.
您不得释放自己未保留的内容(使用
retain
或通过以下方法隐式释放:init
、new
或copy
以他们的名字命名)。如果您保留
fetchFromNetwork
的结果,则必须释放它。release
和autorelease
都应该可以工作(在release
之后不要触摸对象,将字段/变量设置为nil
是最安全的发布
之后的代码>)。如果您不保留数据,那么您甚至不需要保留它。
[NetworkHelper fetchFromNetwork]
应该返回自动释放的对象。fetchFromNetwork
的主体可能如下所示:或者
如果有疑问,请在泄漏方面犯错误并通过“Leaks”仪器或 LLVM 检查器。
You must not release things you have not retained yourself (using either
retain
or implictly by methods with:init
,new
, orcopy
in their name).If you retain result from
fetchFromNetwork
, then you must release it. Bothrelease
andautorelease
should work (don't touch object afterrelease
, it's safest to set fields/variables tonil
afterrelease
).If you're not keeping the data, then you don't even need to retain it.
[NetworkHelper fetchFromNetwork]
should return autoreleased object. Body offetchFromNetwork
could look like this:or
If in doubt, err on the leaky side and run application via "Leaks" Instruments or LLVM checker.