如何在不造成内存泄漏的情况下清除自定义对象的 NSMutableArray?
Posted
技术标签:
【中文标题】如何在不造成内存泄漏的情况下清除自定义对象的 NSMutableArray?【英文标题】:how to clear an NSMutableArray of custom objects without creating memory leaks? 【发布时间】:2011-11-27 15:21:53 【问题描述】:如果我有一个自定义对象的 NSMutableArray,我怎样才能轻松清除数组而不引起任何内存问题?假设自定义对象类中有一个 dealloc 方法,可以正确释放实例变量等。
例如可以使用 NSArray "removeAllObjects" 方法吗?
如果是 - 这是如何工作的 - “removeAllObjects”在删除每个对象时是否调用“dealloc”方法
如果不是 - 最简单的方法是什么?
编辑(4 次回复后) - 在得到很好的回复后的最后一个澄清问题 - 我仍然不太确定我设置为保留的自定义对象中的实例变量/属性?这些似乎只能通过我的自定义对象类中的“dealloc”方法发布,我们在其中手动执行此操作以及 [super release]。
因此,如果重新清除数组,如果我执行 removeAllObjects,然后 NSArray 向我的自定义对象发出“释放”,但不调用“dealloc”,那么我的实例变量如何被释放?
【问题讨论】:
除了内存管理器(或子类的dealloc
)之外,没有人应该调用dealloc
。 removeAllObjects
在每个对象上调用 release
,因为它会从数组中清除它。
是的,如果您在代码中看到不属于[super dealloc];
的dealloc
,那么您做错了。
【参考方案1】:
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。如果一个数组被释放,它里面的所有东西都会被释放,如果没有其他对该对象的引用,它将被释放。
【讨论】:
谢谢 - 如果可以的话,只需在我的问题中添加一个澄清问题作为编辑...... 对不起,我的回答迟了,但是一旦引用计数达到零,系统就会在对象上调用 dealloc。您不必这样做。 使用 ARC 时,系统会以第一种方式正确处理这种情况,不是吗?【参考方案2】:是的,只需致电removeAllObjects
。可以肯定的是,当您将对象添加到数组或创建包含对象的数组时,您不会调用 retain
。这是自动为您完成的。
关于dealloc
,同样会自动完成,你无法预测何时。
dealloc 中唯一需要的就是数组对象本身。也就是说,假设它是一个实例变量或 ivar?
要检查一切是否正常,请使用 Product -> Analyze 运行分析器。然后使用 Leaks 工具在 Instruments 中为应用提供一个配置文件,以检查您的代码是否没有导致任何内存泄漏。
【讨论】:
【参考方案3】:基本上removeAllObjects
方法向所有对象发送release
消息。 release 方法减少对象引用计数。如果一个对象的引用计数达到0
,那么dealloc
消息将被发送到该对象。
您的问题的答案是调用[array removeAllObjects]
是完全安全的。顺便说一句,如果您不再需要该数组,您可以直接调用[array release]
,它会释放其所有对象以及数组。
【讨论】:
你说它按事实发送了一个发布方法。是因为 ARC 吗?【参考方案4】:dealloc
方法永远不会被直接调用。一切都是通过retain
/release
机制(和引用计数原则)完成的。所以这是被调用的release
方法,而不是直接调用的dealloc
。 dealloc
方法仅在最后一次 release
调用导致对象的引用计数 (retainCount) 达到零时才由运行时调用,这意味着该对象确实已从内存中释放,因为没有人再使用它了。
NSArray
和 Cocoa 中的所有容器类(NSDictionary
、NSSet
、...)都保留了它们的值。因此,当您将对象添加到像NSArray
这样的容器时,它将retain
那个值。当您删除该值时(包括调用 removeAllObjects 时),它将release
它。
内存管理规则很容易遵循:但唯一重要的规则是,如果您调用了alloc
、retain
或copy
方法,您只需调用release
或autorelease
。这始终是执行alloc
/retain
/copy
调用release
/autorelease
的对象的责任。永远不要离开 alloc
/retain
/copy
而没有待处理的 release
/autorelease
调用来平衡它(否则你会有泄漏),但另一方面永远不要调用 release
/autorelease
如果你没有做 alloc
/retain
/copy
自己打电话。
好例子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
[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.
好例子2:
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
好例子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
// no need to call "release" here as there is no "alloc" done in the scope of this code
不好的例子:
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!
【讨论】:
谢谢 - 如果可以的话,只需在我的问题中添加一个澄清问题作为编辑......以上是关于如何在不造成内存泄漏的情况下清除自定义对象的 NSMutableArray?的主要内容,如果未能解决你的问题,请参考以下文章
Android面试每日一题: 一般什么情况下会导致内存泄漏问题?
Android面试每日一题: 一般什么情况下会导致内存泄漏问题?