@ property / @合成问题

时间:2011-05-05 19:46:21

标签: iphone objective-c memory-management properties synthesizer

我正在查看有关内存管理的所有文档,我对某些事情感到有些困惑。

使用@property时,它会为对象创建getter / setter:

·H:     @property(retain,nonatomic)NSString * myString

的.m:     @synthesize myString

我理解这一点,但是我感到困惑的地方是使用自我。我在不同的博客和书籍中看到了不同的语法。我见过:

myString = [NSString alloc] initWithString:@"Hi there"];

self.myString = [NSString alloc] initWithString:@"Hi there"];

然后在dealloc中我看到:

self.myString = nil;

[myString release];

self.myString = nil;
[myString release];

在这个网站上,有人说使用self会为保留计数增加另一个增量?是真的,我没有在任何地方见过。

提供自动释放的自动getter / setter吗?

这是完成所有这些的正确方法吗?

谢谢!

3 个答案:

答案 0 :(得分:18)

如果您没有使用点语法,则不使用任何setter或getter。

接下来是,它取决于如何声明属性。

让我们假设这样的事情:

@property (nonatomic, retain) Article *article;
...
@synthesize article;

使用

为文章分配
self.article = [[Article alloc] init];

将覆盖alloc / init返回的实例并导致泄漏。这是因为文章的设置者将保留它并将为您释放任何先前的实例。

所以你可以把它重写为:

self.article = [[[Article alloc] init] autorelease];

这样做

article = [[Article alloc] init]; 

也可以,但可能涉及泄漏,因为文章可能已经拥有对实例的引用。因此,需要事先释放价值:

[article release];
article = [[Article alloc] init]; 

释放内存可以使用

完成
[article release];

self.article = nil;

第一个直接访问该字段,不涉及setter / getters。第二个使用setter将nil设置为字段。如果有当前实例,则将其设置为nil。

此构造

self.myString = nil; 
[myString release];

太多了,它实际上发送给nil,这是无害的,但也是不必要的。

您只需使用点语法精神映射帽子,使用访问器方法:

self.article = newArticle
// is
[self setArticle:newArticle];

myArticle = self.article;
// is
myArticle = [self article];

有关阅读的一些建议,Apple的所有官方文件:

Objective-C编程语言

内存管理编程指南

答案 1 :(得分:1)

当你创建一个retain setter时,你正在创建这样的东西:

- (void)setString:(NSString *)someString {
    if (someString != string) {
        [string release];
        [someString retain];
        string = someString;
    }
}

如果您不使用setter,则新值不会保留 - 您不“拥有”该字符串,并且因为它是所有引用,如果原始字符串被释放,您可能面临null引用,这将导致EXC_BAD_ACCESS。使用setter确保您的类现在具有该值的副本 - 所以是的,它确实增加了新值的保留计数。 (请注意,使用getter是OOP的惯例 - 外人不应该直接触摸ivar。也可以在你的getter中修改值,例如,当你的ivar是NSMutableArray时,可能会返回NSArray)。

你不应该在一个setter中autorelease - Apple已经在他们的示例代码中使用了它,但要记住的是,setter被称为很多次,可能是。所有这些对象都进入相同的自动释放池,所以除非你创建自己的和/或定期刷新它,你的池中将有大量元素,所有元素都不需要但仍占用RAM。简单地release就好了。

至于dealloc,追溯那个setter。如果您直接发送release,很明显 - 您释放该对象。但是如果你写self.string = nil;,那你正在做的是:

  1. nil值不相同,因此您输入if
  2. 您释放旧值 - 您要执行的操作
  3. retain nil:消息为nil什么都不做,你不会崩溃
  4. 你将nil(不占用任何内存)设置为字符串,现在实际上是空的
  5. 作为惯例,我在release方法中使用dealloc,因为release似乎更为最终,dealloc是您的对象将收到的最终方法调用。我在viewDidUnload中使用self.string = nil;和内存警告方法。

    希望这有帮助!

答案 2 :(得分:1)

除了Nick的回答 - 合成的getter / setter不提供自动释放(顺便说一句,这样做有什么好主意?好吧,你可以使用getter作为工厂,但它不是Objective C中的常用方法)。

  

然后在dealloc中我看到:

     

self.myString = nil;

     

     

[myString release];

     

     

self.myString = nil; [myString的   释放];

在dealloc中,您正在使用哪种版本的释放并不重要。但是好的方法是在释放它们时使你的字段为零:)我更喜欢在dealloc中使用self.myString = nil;