10

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

当您使用 @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 会增加保留计数的另一个增量?是真的吗,我在哪里都没见过。

提供的自动获取器/设置器是否自动释放?

做这一切的正确方法是什么?

谢谢!

4

3 回答 3

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/getter。第二个使用 setter 将 nil 设置为字段。如果在将其设置为 nil 之前有一个,它将释放当前实例。

这种构造

self.myString = nil; 
[myString release];

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

您只需要使用点语法在心理上映射帽子就是使用访问器方法:

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

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

关于阅读的一些建议,所有苹果官方文档:

Objective-C 编程语言

内存管理编程指南

于 2011-05-05T19:55:10.670 回答
1

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

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

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

你不应该autorelease在 setter 中——Apple 已经在他们的示例代码中使用了它,但要记住的是,setter 被调用了很多次——可能会被调用数百万次。所有这些对象都将进入同一个自动释放池,因此除非您创建自己的和/或定期刷新它,否则池中将有大量元素,所有这些都不需要但仍占用 RAM。简单得多release

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

  1. nil值不一样,所以进入ifblock
  2. 你释放旧的价值——你想做的事
  3. You retainnil:发给 nil 的消息什么都不做,而且你不会崩溃
  4. 您将不占用任何内存的 nil 设置为字符串,该字符串现在实际上是空的

按照惯例,我release在我的dealloc方法中使用,因为release看起来更最终,并且dealloc是您的对象将收到的最终方法调用。我self.string = nil;在 viewDidUnload 和内存警告方法中使用。

希望这可以帮助!

于 2011-05-05T20:12:27.283 回答
1

除了尼克的回答 - 合成的 getter/setter 不提供自动释放(顺便说一句,这样做的大想法是什么?好吧,您可以将 getter 用作工厂,但这在 Objective C 中不是一种常见的方式)。

然后在 dealloc 我看到:

self.myString = nil;

或者

[myString 发布];

或者

self.myString = nil; [myString 发布];

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

于 2011-05-05T20:13:41.957 回答