指针/内存管理的可可策略

时间:2009-02-22 00:33:28

标签: iphone objective-c cocoa cocoa-touch

我看到很多代码,特别是在Apple示例代码中,类似于以下内容:

   EditingViewController *controller = [[EditingViewController alloc] initWithNibName:@"EditingView" bundle:nil];
    self.editingViewController = controller;
    [controller release];

特别是有任何理由认为上述方法对以下方法有益:

self.editingViewController = [[EditingViewController alloc] initWithNibName:@"EditingView" bundle:nil];

试图了解是否有上述策略。

谢谢!

2 个答案:

答案 0 :(得分:8)

乍一看,您的示例似乎可以正常工作,但事实上它会造成内存泄漏。

按照惯例,在Cocoa和Cocoa-touch中,使用[[SomeClass alloc] initX][SomeClass newX]创建的任何对象都会创建一个保留计数为1的对象。您有责任在完成新实例后致电[someClassInstance release],通常采用dealloc方法。

当你将新对象分配给属性而不是实例变量时,这会变得棘手。大多数属性被定义为retaincopy,这意味着它们可以在设置时增加对象的保留计数,也可以复制对象,保持原始状态不变。

在您的示例中,您可能在.h文件中包含此内容:

@property (retain) EditingViewController *editingViewController;

所以在你的第一个例子中:

EditingViewController *controller = 
    [[EditingViewController alloc] initWithNibName:@"EditingView" bundle:nil];
// (1) new object created with retain count of 1

self.editingViewController = controller;
// (2) equivalent to [self setEditingViewController: controller];
// increments retain count to 2

[controller release];
// (3) decrements retain count to 1

但是对于你的第二个例子:

// (2) property setter increments retain count to 2
self.editingViewController = 

    // (1) new object created with retain count of 1
    [[EditingViewController alloc] initWithNibName:@"EditingView" bundle:nil];

// oops! retain count is now 2

通过在将新对象传递给setter之前调用autorelease方法,您要求自动释放池获取对象的所有权并在将来的某个时间释放它,所以有一段时间该对象具有两个所有者匹配其保留计数,一切都是hunky dory。

// (3) property setter increments retain count to 2
self.editingViewController = 

    // (1) new object created with retain count of 1
    [[[EditingViewController alloc] initWithNibName:@"EditingView" bundle:nil]

        // (2) give ownership to autorelease pool 
        autorelease];

// okay, retain count is 2 with 2 owners (self and autorelease pool)

另一种选择是将新对象直接分配给实例变量而不是属性setter。假设您的代码命名为基础实例变量editingViewController

// (2) assignment to an instance variable doesn't change retain count
editingViewController = 

    // (1) new object created with retain count of 1
    [[EditingViewController alloc] initWithNibName:@"EditingView" bundle:nil];

// yay! retain count is 1

这是代码中的一个微妙但关键的区别。在这些示例中,self.editingViewController = x[self setEditingViewController: x]的语法糖,但editingViewController是一个普通的旧实例变量,没有编译器生成的任何保留或复制代码。

另见Why does this create a memory leak (iPhone)?

答案 1 :(得分:4)

你可以写:

self.editingViewController = [[[EditingViewController alloc] initWithNibName:@"EditingView" bundle:nil] autorelease];

我经常在非速度关键领域做。问题是该属性很可能是一个“保留”属性,这意味着如果你不释放它,该对象将被泄露。

应该注意的是,自动释放比发布更昂贵,但我也更喜欢简洁的代码,以提高纯度的可读性。