Objective-C(iPhone)ivars和内存管理

时间:2010-10-24 15:47:15

标签: iphone objective-c

我正在继承NSURLConnection,并使用MGTwitterEngine作为基础来帮助我开始。这可能是无关紧要的。但是,我注意到他们的代码中没有使用@property@synthesize作为他们的ivars。他们将ivars包裹在访问器方法中,如下所示:

- (NSString *)identifier {
  return [[_identifier retain] autorelease];
}

我的问题是两部分。首先,retain后跟autorelease有什么影响?在我看来它会取消本身,或者更糟糕的是泄漏。

其次,如果我要更改头文件:

@property (nonatomic, retain, readonly) NSString* _identifier;

并使用@synthesize indentifier = _identifier,这不会与访问者方法做同样的事情而不必写它吗?

也许这只是两种不同的方式来做同样的事情。但我想确保我有正确的理解。感谢。

4 个答案:

答案 0 :(得分:8)

使用@synthesize实际上只会创建一个setter和一个getter方法。为您自动生成的代码保证使用适当的内存管理,因此您无需担心。

MGTwitterEngines使用return [[ivar retain] autorelease]实际上是正确的方法。让我们举两个例子。

假设getter定义如下:

-(Foo)foo {
    return foo;
}

然后我们执行此代码:

  1. bar = [[bar alloc] init]; // bar的计数为1。
  2. foo = bar.foo; // foo保留计数为1(由酒吧拥有)。
  3. [bar release]; //酒吧及其所有的ivars都是imidiatetly释放!
  4. [foo doSomething]; //自上一行释放foo以来,这将崩溃。
  5. 如果我们改为将getter更改为:

    -(Foo)foo {
        return [[foo retain] autorelease];
    }
    
    1. bar = [[bar alloc] init]; //栏的保留计数为1
    2. foo = bar.foo; // foo的保留计数为2(一个由bar拥有,一个由autorelease pool拥有)。
    3. [bar release]; //酒吧及其所有的ivars都是imidiatetly释放!
    4. [foo doSomething]; //因为foo仍然存在并且由autorelease池拥有,所以不会崩溃。
    5. 希望这能解释为什么你应该总是从你所有的getter中正确地返回自动释放的对象。重要的是,任何返回值都可以在其父级的解除分配中继续存在,因为没有类可以保证客户端在暴露给野外时对其值的影响。

答案 1 :(得分:3)

保留然后自动释放完全符合您的想法。它向对象发送retain消息,然后向其发送autorelease消息。请记住,自动释放对象会将该对象添加到自动释放池但不会将其释放。自动释放池将在运行循环的当前迭代结束时向对象发送release消息。因此,retain后跟autorelease基本上说,“确保此对象保持不变,直到运行循环的当前迭代结束。”如果您需要将返回值挂起更长时间,则可以保留它。如果没有,不做任何事情,自动释放池将处理它。

在这种情况下,发送retainautorelease消息的字符串是属性。它已由父对象保留。所以你可能想知道为什么这个保留和自动释放的东西呢?好吧,不能保证在运行循环的当前迭代结束之前对象不会释放_identifier。考虑这个例子:

- (NSString *)identifier { return _identifier; }

- (void)aMethod {
    NSString *localId = [self identifier]; // localId refers to _identifier which is only retained by self
    [self methodThatChangesIdentifierAndReleasesItsOldValue];  // self releases _identifier
    NSLog(@"%@", localId); // crash, because localId (old value of _identifier) has been released
}

在这种情况下,返回的标识符不会保留并自动释放。 NSLog行崩溃,因为localId引用了已发布的字符串。但是,如果我们在getter中使用retainautorelease,则不会发生崩溃,因为在运行循环的当前迭代结束之前不会释放localId

据我所知,您使用identifier财产取代会同样出色。它可能不是相同的代码,但效果应该是相同的。

答案 2 :(得分:1)

Apple在Implementing Accessor Methods中解释得很清楚。您引用的方法(Apple称为“技术1”)有助于避免错误,如果调用者为标识符属性分配新值,然后期望检索到的值仍然可用。大部分时间都不需要它,但只返回ivar值就可能导致难以追踪的错误。

答案 3 :(得分:0)

一般来说,如果你要归还一些你不是第一名的东西,那么就会保留自动释放。如果您拥有_identifier并且保留/ alloc / etc与发送到该对象的release / autorelease不匹配,它将只会泄漏。

其次,是的,如果你没有做超出一般样板文件的特殊事情,你通常不必编写标题。 Apple有关于属性的良好文档,我建议如果你仍然模糊,你看看那些。