我试图理解为什么我的应用程序崩溃并且我正在检查我的代码。我非常确定这是 autorelease 的有效使用:(
代码的一部分)
- (NSArray *)allQuestionsFromCategories:(NSArray *)categories {
...
NSMutableArray *ids = [[[NSMutableArray alloc] init] autorelease];
while (sqlite3_step(statement) == SQLITE_ROW) {
[ids addObject:[NSNumber numberWithInt:sqlite3_column_int(statement, 0)]];
}
return [NSArray arrayWithArray:ids];
}
这有效吗? NSArray arrayWithArray 返回一个自动释放对象不是吗?我在理解自动释放对象的范围方面也有一些困难。在调用此代码所属方法的方法中,自动释放的对象(如果是在这种情况下)是否会被池保留?
- (void)codeThatInvokesTheCodeAbove {
NSArray *array = [self.dao allQuestionsFromCategories];
...
}
返回的数组在整个 codeThatInvokesTheCodeAbove 方法中是否有效而不保留它?如果是的话,它的有效期会更长吗?
在理解它的范围以及何时应该保留自动释放对象时遇到一些问题。
I am trying to understand why my application crashes and I am going through my code. I am pretty sure that this is a valid use of autorelease:
(part of the code)
- (NSArray *)allQuestionsFromCategories:(NSArray *)categories {
...
NSMutableArray *ids = [[[NSMutableArray alloc] init] autorelease];
while (sqlite3_step(statement) == SQLITE_ROW) {
[ids addObject:[NSNumber numberWithInt:sqlite3_column_int(statement, 0)]];
}
return [NSArray arrayWithArray:ids];
}
Is this valid? The NSArray arrayWithArray returns an autorelease object doesn't it? I also have some difficulties in understanding the scope of autoreleased objects. Would the autoreleased object (if it is in this case) be retained by the pool through out the method that invoked the method that this code is a part of?
- (void)codeThatInvokesTheCodeAbove {
NSArray *array = [self.dao allQuestionsFromCategories];
...
}
Would the array returned be valid in the whole codeThatInvokesTheCodeAbove
method without retaining it? And if it was, would it be valid even longer?
Got some issues understanding the scope of it, and when I should retain an autorelease object.
发布评论
评论(4)
这是有效的,但是 - 实际上 - 您可以完全跳过
[NSArray arrayWithArray:ids];
,因为不需要创建新数组。自动释放的对象在自动释放池耗尽之前一直有效,这通常在每次运行循环中发生一次(或者在通过 GCD 将内容排队时“定期发生,但在块执行时不会发生”)。
文档比我解释得更好。< /a>
不需要创建不可变数组,因为返回将有效地将
NSMutableArray
向上转换为NSArray
。虽然这在运行时没有意义,但这意味着调用者无法在不使用强制转换来避免警告的情况下编译对返回值的变异方法的调用。在这种情况下进行强制转换以避免警告是邪恶的缩影,没有称职的开发人员会这样做。如果返回的是实例变量,那么,是的,创建不可变副本对于避免后续突变意外“逃逸”至关重要。
你读过内存管理文档吗?具体来说,关于自动释放池?它非常清楚地说明了自动释放是如何工作的。我讨厌解释一部权威的作品。
That is valid, but -- really -- you can just skip the
[NSArray arrayWithArray:ids];
entirely as there is no need to create a new array.An autoreleased object is valid until the autorelease pool is drained, which typically happens once per pass through a run loop (or "periodically, but never while your block is executing" when enqueuing stuff via GCD).
The documentation explains it all better than I.
There is no need to create an immutable array because the return will effectively "up cast" the
NSMutableArray
toNSArray
. While this is meaningless at run time, it means that the caller cannot compile a call to a mutating method of the returned value without using a cast to avoid the warning. Casting to avoid warnings in this context is the epitome of evil and no competent developer would do that.If it were an instance variable being returned then, yes, creating an immutable copy is critical to avoid subsequent mutations "escaping" unexpectedly.
Have you read the memory management documentation? Specifically, the part about autorelease pools? It makes it quite clear how autorelease works. I hate to paraphrase a definitive work.
[NSArray arrayWithArray:]
返回一个自动释放的对象。如果您希望 codeThatInvokesTheCodeAbove 取得数组的所有权,您应该对其调用retain
(并根据苹果的指南重命名codeThatInvokesTheCodeAbove
)。否则,如果您不关心对象的所有权不明确,那么您的代码就可以。换句话说,
[NSArray arrayWithArray:]
返回一个您不拥有的数组,但您至少可以在此运行周期内访问它。因此,codeThatInvokesTheCodeAbove
至少在此运行周期内可以访问它。所有权不明确,因为没有人调用alloc
、copy
、new
、mutableCopy
或retain< /代码>。这意味着 NSArray 在返回新数组之前调用了 autorelease,从而放弃了所有权。
我的信息来自 http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html%23//apple_ref/doc/uid/20000994-BAJHFBGH。
因此,为了回答您的问题,是的,您发布的代码是有效的。它是否正确取决于您想要实现的目标。
[NSArray arrayWithArray:]
returns an autoreleased object. If you wantcodeThatInvokesTheCodeAbove
to take ownership of the array, you should callretain
on it (and renamecodeThatInvokesTheCodeAbove
according to apple's guidelines). Otherwise, if you don't care that ownership of the object is ambiguous then your code is okay.In other words,
[NSArray arrayWithArray:]
returns an array that you don't own, but you have access to it for at least this run cycle. Therefore,codeThatInvokesTheCodeAbove
will have access to it for at least this run cycle. Ownership is not clear, since nobody calledalloc
,copy
,new
, ormutableCopy
orretain
. It is implied thatNSArray
called autorelease before returning the new array, thus relinquishing ownership.My information comes from http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html%23//apple_ref/doc/uid/20000994-BAJHFBGH.
So, to answer your question, yes your posted code is valid. Whether it's correct depends on what it is you are trying to accomplish.
自动释放的对象是标记为稍后释放的对象。
有一个非常特殊的对象是由 UIApplicationMain 自动创建的:UIRunLoop。
例如,将其想象为一个 while 结构,它循环直到应用程序终止,它接收每个事件并将其正确地重新发送到您感兴趣的类。在 UIApplicationMain 之前有一个命令来创建一个 NSAutoreleasePool,一旦 NSRunLoop 准备好,就附加到它。当你向一个对象发送
-autorelease
命令时,NSAutoreleasePool会记住在释放它自己时释放它。在内存较少的平台(iOS 设备)中多次使用它是危险的,因为当您发送-autorelease
命令时,对象不会被释放,而是当 NSAutoreleasePool 耗尽时(当应用程序释放它时) 。Autoreleased object are objects that are marked as to be release later.
There is a very particular object that is automatically created by UIApplicationMain: an UIRunLoop.
Imagine it like a
while
structure, it cycle until application is terminate, it receives every event and properly resend it to your interested classes, for example. Just before UIApplicationMain there is a command to create an NSAutoreleasePool that, once the NSRunLoop is ready, attach to it. When you send an-autorelease
command to an object, the NSAutoreleasePool will remember to release it when is released itself. It's dangerous to use it many times in platforms that has less memory (iOS devices), because objects aren't released when you send an-autorelease
command but when the NSAutoreleasePool is drained (when app releases it).如果您想在返回之前释放非可变列表,您可以使用类似以下内容:
除非您的可变数组有时可能会使用大量内存,否则不值得这样做。
If you want to free the non-mutable list before you return, you can use something like this:
It is not worth doing this unless your mutable array is likely to sometimes use a lot of memory.