NSArray 内存管理
Posted
技术标签:
【中文标题】NSArray 内存管理【英文标题】:NSArray Memory Management 【发布时间】:2010-09-08 14:44:29 【问题描述】:由于某种原因,当我释放 NSArray 时,我得到了 EXC_BAD_ACCESS 异常。这是实现:
-(void) loadAllAlphabets
NSBundle *bundle = [NSBundle mainBundle];
NSArray *imagesPath = [[NSArray alloc] init];
imagesPath = [bundle pathsForResourcesOfType:@"png" inDirectory:@"Images"];
alphabets = [[NSMutableArray alloc] init];
NSString *fileName = [[NSString alloc] init];
for(int i=0; i<= imagesPath.count -1 ; i++)
fileName = [[imagesPath objectAtIndex:i] lastPathComponent];
CCSprite *sprite = [CCSprite spriteWithFile:fileName];
sprite.userData = [[fileName stringByDeletingPathExtension] uppercaseString];
[alphabets addObject:sprite];
// release fileName
[fileName release];
fileName = nil;
[imagesPath release]; // this causes the application to crash with EXC_BAD_ACCESS
// imagesPath = nil;
更新 1:
所以,问题在于,虽然我负责释放 imagesPath 对象,因为我使用了 alloc,但当 pathForResourcesOfType 返回一个自动释放对象时,它很快就变得无关紧要了。 这意味着我不应该手动释放 imagesPath 对象。
应使用以下行:
NSArray *imagesPath = [bundle pathsForResourcesOfType:@"png" inDirectory:@"Images"];
更新 2:
另一个与这篇文章相关的问题。在下面的代码中,我手动初始化了一个新的 NSMutableArray。
alphabets = [[NSMutableArray alloc] init];
稍后我将 CCSprite(Cocos2d 对象)插入到字母数组中。 CCSprite 是自动释放对象。我还需要手动释放字母吗?因为,一段时间后,所有对象都被释放并且内存将被返回,但是字母 NSMutable 数组中会留下什么?
【问题讨论】:
当您将 imagesPath 重新分配给 pathsForResourcesOfType: 调用时会发生泄漏,因为您已经分配了并且 i 【参考方案1】:我认为混乱就在这里:
NSArray *imagesPath = [[NSArray alloc] init];
imagesPath = [bundle pathsForResourcesOfType:@"png" inDirectory:@"Images"];
第一行创建一个新对象。这个对象确实需要释放。
第二行用一个新的、自我管理的对象覆盖该对象。这不需要手动释放。
这意味着您正在泄漏第一个 imagesPath。
一般情况下,如果你alloc
或copy
它,你需要释放一个对象。并且您不应该在释放(或自动释放)其内容之前覆盖对象。
【讨论】:
【参考方案2】:内存管理中的一般经验法则 - 只有在使用包含 new、copy 或 alloc 的方法获取对象时才应该释放对象(标准方法遵循该规则,您也应该遵守该规则)。
在您的情况下,您使用 pathsForResourcesOfType:
方法获取 imagesPath 对象,该方法返回一个自动释放的对象,因此您不能自己释放它。
编辑: 是的,您需要在某处释放alphabets
对象(出于同样的原因 - 您使用 alloc 方法得到了它)。
Objective-c 容器拥有添加到它们的对象的所有权,当我们将对象添加到数组时,它们会被保留,因此可以保证它们的生命周期至少与容器的生命周期一样长。当您从集合中删除对象或集合本身被销毁时,其成员将被释放(以补偿添加时的保留)。
【讨论】:
谢谢弗拉基米尔!因此,即使我分配了 imagesPath,pathsForResourcesOfType 也返回了一个我不能手动释放的自动释放对象。【参考方案3】:此外,当您使用空的非可变数组初始化 imagesPath
时,您正在泄漏内存,然后当您将 pathsForResources:
的结果分配给它时将其丢弃。只需这样做:
NSArray *imagesPath = [bundle pathsForResourcesOfType:@"png" inDirectory:@"Images"];
fileName
出现同样的错误。不需要用一个空的不可变字符串来初始化它。
也不要释放fileName
,因为它也是一个自动释放的对象。
【讨论】:
fileName 是 autorelease 对象的原因是它来自于 imagesPath NSArray 对吧? 另外,如果我正在运行一个循环并分配 fileName 是否意味着我正在为每个循环计数创建新的 NSString 对象。 @azamsharp 是的,'fileName = [[NSString alloc] init];' 行中的值当您在循环内为其分配自动释放的字符串时,将被丢弃。就个人而言,我会在循环之前用 nil 初始化 fileName 是的,您在每次循环迭代时创建一个字符串对象,但这些字符串是自动释放的,因此运行时会自行处理它们 - 您无需担心它们 我刚刚在循环外创建了一个 NSString *fileName = nil。以上是关于NSArray 内存管理的主要内容,如果未能解决你的问题,请参考以下文章