是什么增加了对象的保留计数?

时间:2009-07-25 02:26:07

标签: objective-c memory memory-management retain

以下是我所指的代码。

// Person.h

@interface Person : NSObject {
    NSString *firstName;
    NSString *lastName;
}
@end

// Person.m

@implementation Person
- (id)init {
    if (![super init]) return nil;
    firstName = @"John";
    lastName = @"Doe";
}
@end

// MyClass.m

@implementation MyClass
    .....
- (NSArray *)getPeople {
    NSMutableArray *array = [[NSMutableArray alloc] init];

    int i;
    for (i = 0; i < 10; i++) {
        Person *p = [[Person alloc] init];
        [array addObject:p];
    }

    return array;
}
    .....
@end

现在,我知道此示例代码中没有内存管理。需要什么?

在getPeople循环中,我分配了一个Person(retainCount 1),然后将它添加到数组中。保留计数现在是2,对吗?如果它是两个,我应该在将它添加到数组之后[p release],将retainCount恢复为1吗?

我是否正确,调用者有责任释放该方法返回的数组? (这也可以释放Person的内存及其实例变量,假设它们的计数为1)。

我已经阅读了Apple的内存管理文档,但我想我最不清楚的是,增加对象保留的数量是多少?不过,我想我已经掌握了释放谁的责任的想法。据Apple称,这是基本规则:

  

如果使用名称以“alloc”或“new”开头或包含“copy”(例如,alloc,newObject或mutableCopy)的方法创建对象,或者如果发送它,则获取对象的所有权保留信息。您有责任使用release或autorelease放弃您拥有的对象的所有权。在收到对象的任何其他时间,您都不能释放它。

bobDevil的句子“只担心你明确添加到项目中的保留计数”让它点击给我。在阅读Apple的所有权政策之后,基本上,创建新对象的对象/方法是负责释放/它/兴趣的对象/方法。这是对的吗?

现在,假设我是一个接收对象的方法,并将其分配给实例变量。我需要保持收到的对象正确,因为我仍然对它有兴趣吗?

如果其中任何一项不正确,请与我们联系。

3 个答案:

答案 0 :(得分:18)

将数据添加到数组后,保留计数为2是正确的。但是,您应该只担心显式添加到项目中的保留计数。

保留一个物品是一份合同,上面写着“我没有和你做过,也不要离开。”一个基本的经验法则(有例外,但通常记录它们)是你在分配对象或创建副本时拥有对象。这意味着您将获得保留计数为1(未自动释放)的对象。在这两种情况下,您应该在完成后释放它。此外,如果您明确保留了对象,则必须将其释放。

因此,为了特定于您的示例,当您创建Person时,您有一个保留计数。你把它添加到一个数组(使用它做什么,你不关心)然后你完成了Person,所以你释放它:

Person *p = [[Person alloc] init]; //retain 1, for you
[array addObject:p]; //array deals with p however it wants
[p release]; //you're done, so release it

另外,正如我上面所说,你只在alloc或copy期间拥有该对象,所以为了与事物的另一面保持一致,你应该返回自动释放的数组,以便getPeople方法的调用者做不拥有它。

return [array autorelease];

编辑:    正确,如果你创建它,你必须释放它。如果您对此感兴趣(通过保留),您必须将其释放。

答案 1 :(得分:4)

当您专门调用alloc时,保留计数会增加,因此您需要明确释放它。

工厂方法通常会为您提供一个自动释放的对象(例如[NSMutableArray数组] - 您必须专门保留它以使其保持一段时间。)。

就NSArray和NSMutableArray addObject:而言,其他人必须发表评论。我相信你把一个类视为黑盒子,就如何将自己的内存管理作为一种设计模式来处理,所以你永远不会明确地发布你已经传递给NSArray的内容。当它被破坏时,它应该处理减少保留计数本身。

如果将ivars声明为@property(retain)suchAndSuchIvar等属性,并在实现中使用@synthesize,也可以获得一些隐式保留。 Synthesize基本上为你创建了setter和getter,如果你专门调出(retain),setter将保留传入它的对象。它并不总是很明显,因为setter的结构可以这样:

Person fart = [[Person alloc] init];
fart.firstName = @"Josh"; // this is actually a setter, not accessing the ivar
                          // equivalent to [fart setFirstName: @"Josh"], such that
                          // retainCount++

编辑:

就内存管理而言,只要将对象添加到数组中,就完成了它......所以:

   for (i = 0; i < 10; i++) {
       Person *p = [[Person alloc] init];
       [array addObject:p];
       [p release];
   }

约什

答案 2 :(得分:2)

您通常/不应该/担心保留计数。这是内部实施的。您应该只关心是否要通过保留对象来“拥有”对象。在上面的代码中,数组应该拥有对象,而不是你(在循环之外你甚至没有通过数组引用它)。因为你拥有[[Person alloc] init],所以你必须释放它。

因此

Person *p = [[Person alloc] init];
[array addObject:p];
[p release];

此外,“getPeople”的调用者不应该拥有该数组。这是惯例。你应该先自动发布它。

NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease];

您需要阅读Apple关于内存管理的文档:http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html

相关问题