我试图理解为什么我的应用程序崩溃并且我正在浏览我的代码。我很确定这是自动释放的有效用途:
(部分代码)
- (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返回一个autorelease对象吗?我在理解自动释放对象的范围方面也遇到了一些困难。自动释放的对象(如果是在这种情况下)是否会通过调用此代码所属方法的方法保留池?
- (void)codeThatInvokesTheCodeAbove {
NSArray *array = [self.dao allQuestionsFromCategories];
...
}
返回的数组在整个codeThatInvokesTheCodeAbove
方法中是否有效而不保留它?如果是的话,它会更长有效吗?
了解其范围时遇到了一些问题,以及何时应该保留自动释放对象。
答案 0 :(得分:4)
这是有效的,但是 - 实际上 - 您可以完全跳过[NSArray arrayWithArray:ids];
,因为不需要创建新数组。
自动释放的对象在自动释放池耗尽之前一直有效,这通常在每次通过运行循环时发生一次(或“通过GCD将事件排入队列时定期执行,但从不在块执行时”)。
The documentation explains it all better than I.
无需创建不可变数组,因为返回将有效地“向上转换”NSMutableArray
到NSArray
。虽然这在运行时没有意义,但这意味着调用者无法编译对返回值的变异方法的调用,而不使用强制转换来避免警告。在这种情况下避免警告的铸造是邪恶的缩影,没有能干的开发者会这样做。
如果它是一个返回的实例变量,那么,是的,创建一个不可变副本对于避免后续突变“意外逃逸”至关重要。
您是否阅读过内存管理文档?具体来说,关于autorelease pools的部分?它很清楚自动释放是如何工作的。我不想解释一项明确的工作。
答案 1 :(得分:1)
[NSArray arrayWithArray:]
返回一个自动释放的对象。如果您希望codeThatInvokesTheCodeAbove
获得数组的所有权,则应在其上调用retain
(并根据Apple的指南重命名codeThatInvokesTheCodeAbove
)。否则,如果您不关心对象的所有权是不明确的,那么您的代码就可以了。
换句话说,[NSArray arrayWithArray:]
返回一个您不拥有的数组,但至少在此运行周期内您可以访问它。因此,codeThatInvokesTheCodeAbove
至少可以在此运行周期内访问它。所有权不明确,因为没有人打电话给alloc
,copy
,new
或mutableCopy
或retain
。隐含的是NSArray
在返回新数组之前调用autorelease,从而放弃了所有权。
所以,回答你的问题,是的,你发布的代码是有效的。它是否正确取决于你想要完成的是什么。
答案 2 :(得分:1)
自动释放的对象是标记为稍后释放的对象。
有一个非常特殊的对象由UIApplicationMain自动创建:UIRunLoop。
想象它就像一个while
结构,它循环直到应用程序终止,它接收每个事件并正确地将它重新发送给你感兴趣的类。就在UIApplicationMain之前,有一个命令来创建一个NSAutoreleasePool,一旦NSRunLoop准备就绪,就会附加到它。当您向对象发送-autorelease
命令时,NSAutoreleasePool会记得在释放时释放它。在具有较少内存的平台(iOS设备)中多次使用它是危险的,因为当您发送-autorelease
命令但是当NSAutoreleasePool被耗尽时(当应用程序释放它时),对象不会被释放。
答案 3 :(得分:0)
如果您想在返回之前释放非可变列表,可以使用以下内容:
- (NSArray *)allQuestionsFromCategories:(NSArray *)categories {
...
NSArray* result;
NSMutableArray *ids = [[NSMutableArray alloc] init]; // AUTORELEASE REMOVED FROM HERE
while (sqlite3_step(statement) == SQLITE_ROW) {
[ids addObject:[NSNumber numberWithInt:sqlite3_column_int(statement, 0)]];
}
result = [NSArray arrayWithArray:ids]; // COPY LIST BEFORE IT IS FREED.
[ids release]; // MUTABLE LIST FREES _NOW_
return result; // NONMUTABLE COPY IS RETURNED
}
除非你的可变数组有时可能会占用大量内存,否则不值得这样做。