如何在不创建内存泄漏的情况下清除自定义对象的NSMutableArray?

时间:2011-09-29 11:28:06

标签: iphone objective-c ios memory-leaks nsmutablearray

如果我有自定义对象的NSMutableArray,我怎样才能轻松清除数组而不会导致任何内存问题?假设自定义对象类中有一个dealloc方法,它正确地释放了一个实例变量等。

例如,可以使用NSArray“removeAllObjects”方法吗?

  • 如果是 - 这是如何工作的 - “removeAllObjects”在删除每个对象时调用“dealloc”方法

  • 如果不是 - 最简单的方法是什么?

编辑(4回复后) - 在回复之后的最后一个澄清问题 - 我仍然不太确定我设置为保留的自定义对象中的实例变量/属性?这些似乎只能通过我的自定义对象类中的“dealloc”方法释放,我们手动执行此操作以及[super release]。

因此,如果重新清除数组,如果我执行removeAllObjects,然后NSArray向我的自定义对象发出“释放”,但不调用“dealloc”,那么我的实例变量如何被释放?

4 个答案:

答案 0 :(得分:32)

removeAllObjects将从数组中删除该对象。此过程将向对象发送释放消息,这将减少其引用计数。当引用计数达到零时,对象将被释放。

不要这样做,因为它会泄漏。

NSObject *object = [[NSObject alloc] init];       + 1
[array addObject:object];                         + 1
[array removeAllObjects];                         - 1
                                                =======
                                                = + 1 -> Leak

这是正确的方法:

NSObject *object = [[[NSObject alloc] init] autorelease]; + 1 (from alloc) - 1 (from autorelease)
[array addObject:object];                         + 1
[array removeAllObjects];                         - 1
                                                =======
                                                =   0 -> Object will be deallocated

您可以只释放数组,而不是调用removeAllObjects。如果一个数组被释放,那么它内部的所有东西都会被释放,如果没有对该对象的其他引用,它将被解除分配。

答案 1 :(得分:3)

是的,只需致电removeAllObjects。可以肯定的是,在向数组添加对象或创建包含对象的数组时,不要调用retain。这是自动完成的。

关于dealloc,将再次自动完成,您无法预测何时。

你需要在dealloc中唯一拥有的是数组对象本身。也就是说,假设它是一个实例变量或ivar?

要检查一切正常,请使用Product运行Analyzer - >分析。然后使用Leaks仪器在应用程序中为应用程序提供配置文件,以检查您的代码是否都没有导致任何内存泄漏。

答案 2 :(得分:1)

永远不会直接调用dealloc方法。一切都通过retain / release机制(以及引用计数原则)完成。因此,这是被调用的release方法,而不是直接调用dealloc。如果最后dealloc调用导致对象的引用计数(retainCount)达到零,则release方法仅由运行时调用,这意味着该对象实际上已从内存中释放,因为没有人再使用它。

NSArray并且Cocoa中的所有容器类(NSDictionaryNSSet,...)都会保留其值。因此,当您将objet添加到NSArray之类的容器时,它将retain该值。当你删除该值(包括调用removeAllObjects时),它将release它。

内存管理规则很容易遵循:但唯一重要的规则是,如果您拨打releaseautorelease或者alloc,则只需拨打retaincopy alloc方法。这始终是objet的责任,它使retain / copy / release调用autorelease / alloc。永远不要离开retain / copy / release而没有待处理的autorelease / release来平衡它(或者你会有泄漏),但另一方面如果您没有亲自拨打autorelease / alloc / retain来电话,请勿拨打copy / MyClass* obj = [[MyClass alloc] init]; // here you do an alloc [myArray addObject:obj]; // the NSArray "myArray" retains the object obj // so now you can release it, the array has the responsability of the object while it is held in the array [obj release]; // this release balance the "alloc" on the first line, so that's good [myArray removeAllObjects]; // there the object held by the array receive a release while being removed from the array. As nobody retains it anymore, its dealloc method will be called automatically.

好榜样1:

MyClass* obj = [[MyClass alloc] init]; // here you do an alloc
[myArray addObject:obj]; // the NSArray "myArray" retains the object obj
// so now you can release it, the array has the responsability of the object while it is held in the array
[myArray removeAllObjects]; // there the object held by the array receive a release while being removed from the array. But your own code still retains a reference to it (because of the "alloc" on first line) so it won't be removed from memory right now
[obj release]; // this release balance the "alloc" on the first line, and as nobody retains the object anymore, its dealloc method will be called and it will be deallocated from memory

好榜样2:

MyClass* obj = [self getSomeObjectFromAnotherMethod]; // here you don't have an "alloc" on this line
[myArray addObject:obj]; // the array retains the object
[myArray removeAllObjects]; // the array release the object while it removes it from the array
// no need to call "release" here as there is no "alloc" done in the scope of this code

好榜样3:

MyClass* obj = [self getSomeObjectFromAnotherMethod]; // here you don't have an "alloc" on this line
[myArray addObject:obj]; // the array retains the object
[myArray removeAllObjects]; // the array release the object while it removes it from the array
[obj release]; // Crash here! obj does not exists anymore and has been deallocated from memory before this line!

错误的例子:

{{1}}

答案 3 :(得分:1)

基本上removeAllObjects方法会向所有对象发送release消息。 发布方法 减少对象引用计数 。如果对象的引用计数达到0,则dealloc消息将被发送到对象。

您的问题的答案是致电[array removeAllObjects]是完全安全的。顺便说一下,如果你不再需要数组,你可以直接调用[array release]来释放它的所有对象以及数组。