【问题标题】:Cocoa strategy for pointer/memory management指针/内存管理的 Cocoa 策略
【发布时间】:2009-02-22 00:33:27
【问题描述】:

我看到很多代码,尤其是 Apple 示例代码,类似于以下内容:

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

是否有任何理由证明上述方法对以下方面有益:

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

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

谢谢!

【问题讨论】:

    标签: iphone objective-c cocoa cocoa-touch


    【解决方案1】:

    乍一看,您的示例似乎可行,但实际上它会造成内存泄漏。

    按照 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)
    

    另一种选择是将新对象直接分配给实例变量而不是属性设置器。假设您的代码将底层实例变量命名为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)?

    【讨论】:

    • @property (retain) EditingViewController *editingViewController; // (2) 属性设置器将保留计数增加到 2 self.editingViewController = // (1) 使用保留计数 1 创建的新对象 [[EditingViewController alloc] initWithNibName:@"EditingView" bundle:nil]; // 哎呀!保留计数现在是 2 这不是真的。编译器创建的setter方法会释放作为参数传递的对象,并保留属性。所以保留计数为1,没有问题。
    【解决方案2】:

    你可以写:

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

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

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

    【讨论】:

    • 即使是复制属性,也会泄露。
    • 我想你最后错过了自动释放的电话。
    猜你喜欢
    • 2016-09-24
    • 1970-01-01
    • 2013-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-19
    • 1970-01-01
    • 2011-03-12
    相关资源
    最近更新 更多