内存管理属性如何影响数组的单元格?

时间:2011-04-24 05:23:28

标签: iphone objective-c cocoa-touch memory-management

在我的iPhone开发书中,我看到一些奇怪的编码示例,关于当对象添加到数组时以及释放整个数组时数组的作用。一个代码示例在实例数组上具有以下属性:

@property (nonatomic, retain) NSMutableArray* myArray;

作者向数组添加一个对象,然后立即释放指向该对象的指针。阵列单元现在不会指向垃圾数据吗?除非在幕后,阵列单元格在添加时保留对象。

SomeObject* someObject = [[SomeObject alloc] init];
[self.myArray addObject:someObject];
[someObject release];

作者还会释放指向数组的指针,而不首先遍历每个数组单元并释放单个对象。这是内存泄漏,除非在后台发送每个单元格 release 消息;。

- (void)viewDidUnload {
    self.myArray = nil;
    [super viewDidUnload];
}

4 个答案:

答案 0 :(得分:2)

  

除非在幕后,阵列单元格在添加时保留对象。

是的,这种情况发生了。

  

......除非在幕后,每个单元格都会发送一条释放消息。

这也会发生。

您已回答了自己的问题。

以下是Collections Programming Topics的引用:

  

当你添加一个对象时   NSMutableArray对象,该对象   未复制,(除非您将YES传递给   争论的   initWithArray:copyItems :)。相反,一个   object直接添加到数组中。   在托管内存环境中,   对象在收到保留消息时   它被添加;在垃圾收集   环境,它是强烈的   引用。当一个数组是   在托管内存中释放   环境中,每个元素都发送一个   发布消息。

答案 1 :(得分:2)

与C或C ++不同,你经常担心是否删除一个对象,因为担心它仍在其他地方使用,Objective-C(或者说它实际上是Cocoa SDK)使用引用计数机制或者所有权。

您可能已经知道它是如何工作的,但您还需要知道在Cocoa中,如果对象A需要使用另一个对象B,它应该拥有(即保留)它。该对象A不应该依赖于已经保留B的其他对象C,因为它无法知道C何时释放它。因此,在您的情况下,由于NSArray需要在其生命周期中使用添加到其中的所有对象,因此需要保留所有对象。因此,当数组被解除分配时,它需要释放它们。

当你处理大量物品时,这个“你需要保留你想要使用的东西”的概念非常重要。

答案 2 :(得分:1)

苹果开发指南中有几个地方可以解释如果您打算稍后使用它,那么获取对象的所有权(发送保留消息)是一种很好的做法。您应该这样做,以便在您仍然可能需要访问它时不会销毁该对象。

考虑到这一点,你是正确的假设NSArray在将对象添加到集合时会保留该对象,因为它后来仍然可能尝试访问它。

您可以查看“内存管理编程指南”

  

将对象添加到集合(如数组,字典或集合)时,集合将获得对象的所有权。

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmPractical.html#//apple_ref/doc/uid/TP40004447-SW3

或收藏集编程主题了解更多详情

  

...在托管内存环境中,对象在添加时会收到保留消息。

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Collections/Articles/Arrays.html#//apple_ref/doc/uid/20000132-SW1

答案 3 :(得分:1)

  • 第一点你是对的。将对象添加到数组时,该数组将保留该对象。因此,对于之前保留的对象,必须在将其添加到阵列后将其释放,否则最终会导致内存泄漏。

  • 同样,删除对象时 从数组中,数组释放出来 宾语。所以,如果你想保留它, 你需要保留它。

  • 发布数组时,就像你一样 推测,阵列将全部释放 它包含的对象。从而, 单独释放每个对象是 事实上,没有必要 提出异常。

  • 最后,关于代码行 在你引用的-viewDidUnload中:

    self.myArray = nil;
    

只要myArray属性合成如下,这在内存管理方面就可以正常工作:

@synthesize myArray;

Synthesizing创建一个有效执行以下操作的setter:

- (void)setMyArray(NSMutableArray *)anArray
{
    if (![myArray isEqual:anArray]) {
        [myArray release];
        myArray = anArray;
        [myArray retain];
    }
}

因此,当调用时,上面的setter将首先释放旧数组(只要它与新数组不是同一个对象。)然后,它将保留新数组,在这种情况下为nil。请注意,保留nil将不执行任何操作,并且不会触发错误。

当然,如果你没有合成myArray属性,或者你覆盖了setter,你将会遇到内存问题,除非你还发布了旧的值&将新内容保留在你的二传手中。