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

3

我在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];
}

你的“unless”实际上都是正确的。NSMutableArray的addObject会保留对象,当数组被释放时,所有保留的对象都会被释放。 - Lukman
这是因为数组具有retain属性,还是所有NSMutableArray都表现出这种行为?这方面的文档在哪里? - JoJo
请查看我的回答,关于“你需要保留想要以后使用的内容”的概念 :) - Lukman
4个回答

2
“除非在幕后,当添加对象时,数组单元格保留该对象。”是这样的。
“…除非在幕后,每个单元格都被发送释放消息。”也是这样的。
你已经回答了自己的问题。
以下是Collections Programming Topics中的一句话:
“当你将一个对象添加到NSMutableArray对象时,该对象不会被复制(除非你将YES作为initWithArray:copyItems:的参数传递)。相反,对象直接添加到数组中。在托管内存环境中,当添加对象时,对象会收到一个保留消息;在垃圾收集环境中,它被强烈引用。在托管内存环境中,当一个数组被解除分配时,每个元素都会收到一个释放消息。”

2
与C或C++不同,你不必担心是否删除了某个对象,因为它可能仍在其他地方使用。Objective-C(或者更确切地说是Cocoa SDK)使用引用计数或所有权机制。你可能已经知道这个机制的工作原理,但你还需要知道,在Cocoa中,如果一个对象A需要使用另一个对象B,它应该拥有(即保留)它。对象A不应该依赖于其他已经保留B的对象C,因为它无法知道C何时释放它。因此,在你的情况下,由于NSArray需要在其生命周期内使用添加到其中的所有对象,它需要保留所有这些对象。因此,当数组被释放时,它需要释放它们。当你处理大量对象时,“你需要保留你想要稍后使用的对象”这个概念非常重要。

1
  • 首先,你说的是对的。当一个对象被添加到数组中,数组会保留这个对象。因此,对于之前已经保留过的对象,在将其添加到数组后,需要将其释放,否则可能导致内存泄漏。

  • 同样地,当一个对象从数组中移除时,数组会释放该对象。所以,如果你想要保留它,你需要对它进行保留。

  • 当释放一个数组时,如你所猜测的那样,数组会释放它包含的所有对象。因此,释放每个对象并不是必要的,事实上,这样做会引发异常。

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

    self.myArray = nil;
    

只要myArray属性按照以下方式合成,这个程序在内存管理方面就能正常工作:

@synthesize myArray;

合成会创建一个有效执行以下操作的 setter:

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

因此,当调用上述setter时,它将首先释放旧数组(只要它不是与新数组相同的对象)。然后,它将保留新数组,这种情况下为nil。请注意,保留nil将什么也不做,不会触发错误。

当然,如果您不合成myArray属性,或者覆盖了setter,则除非您在setter中释放旧值并保留新值,否则会出现内存问题。


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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接