2

仍然对 Objective-C 内存管理有点困惑。我认为我的困惑源于自动释放的确切含义。

NSString *theBackendResponse = [[NSString alloc] initWithData:receivedData encoding:NSASCIIStringEncoding];
NSDictionary *accountDictionary = [theBackendResponse propertyList];
[viewController setAccountDictionary:accountDictionary];

现在,我应该如何处理视图控制器的 setAccountDictionary 方法中的 accountDictionary?现在我只是将实例变量“accountDictionary”设置为返回的任何内容。我应该将其设置为保留的,然后释放返回的吗?鉴于 NSString 的 propertyList 方法是自动释放的,我的 setter 代码块应该是什么样子?

顺便说一句,如果我释放了BackendResponse,我会丢失accountDictionary吗?我假设不是...

4

4 回答 4

14

调用[objectInstance autorelease]将对象添加到当前NSAutoreleasePool. 当该池收到drain消息时,它会向release池中的所有对象发送一个消息。如果这些对象中的任何一个的 retainCount 达到 0,它们就会在此时被释放。autorelease 的目的是允许您标记要在“未来某个时间”释放的对象。这对于返回一个新分配的对象但想要释放它的方法特别有用,这样调用者就不必拥有返回的对象的所有权。一个方法可能如下所示:

- (id)myMethod {
    id myObj = [[SomeClass alloc] init];

    ...

    return [myObj autorelease];
}

如果他们想要获得返回值的所有权,则调用者myMethodretain返回返回值,否则将忽略它。当电流NSAutoreleasePool耗尽时,myObj会得到一个释放信息。如果没有其他对象拥有它(即已向其发送retain消息),它将被释放。

所有这些都在 Cocoa内存管理编程指南中进行了解释。即使你已经读过它,它总是值得再读一遍。

所以,回答你的问题:

首先,你应该释放theBackendResponse. 如果不这样做,您将泄漏内存。您不需要知道accountDictionary字符串的作用:如果它需要保留引用,它将保留theBackendResponse。您拥有 的所有权,theBackendResponse因为您拥有alloc它,因此您必须放弃该所有权(通过release或间接通过autorelease)。

setAccountDictionary:其次,如果要分别保留对该对象或值的引用,则必须保留或复制参数。标准的 setter 方法看起来像这样(假设您不需要原子语义):

-(void)setAccountDictionary:(NSDictionary*)newDict {
  if(newDict != accountDictionary) {
    id tmp = accountDictionary;
    accountDictionary = [newDict copy]; //Since newDict may be mutable, we make a copy so that accountDictionary isn't mutated behind our back.
    [tmp release];
  }
}

您还必须记住release在 dealloc 方法中使用 accountDictionary:

- (void)dealloc {
    [accountDictionary release];
    [super dealloc];
}

由于您似乎正在使用NSViewController,我假设您使用的是 Leopard (OS X 10.5),在这种情况下,您可能应该使用@propertyd @synthesizegetter/setter(如果可能)。为此,添加一个

@property (copy,readwrite) NSDictionary * accountDictionary; 

向班级声明@interface。并在你的控制器类的块中添加一个@synthesize accountDictionary;指令。@implementation

于 2009-06-09T17:03:18.637 回答
4

通常,一个对象或方法不必关心另一个对象或方法如何管理内存。其他人自动发布某些东西的事实与您无关。考虑所有权的概念更简单。所以retain和其他一些方法声称拥有所有权,release然后autorelease放弃它。如果一个对象需要保留对另一个对象的引用,它应该在需要时声明所有权。因此,setter 方法通常要么保留或复制新值,然后释放或自动释放旧值。

我强烈推荐阅读Cocoa 内存管理指南。它们并不长也不复杂,理解它们非常重要。

于 2009-06-09T17:15:20.367 回答
3

在旧值是唯一拥有新值的对象的情况下,set 访问器方法应该始终copy/释放旧值之前的传入值:retain

-(void)setAccountDictionary:(NSDictionary*)newDict {
    id old = accountDictionary;
    accountDictionary = [newDict copy];
    [old release];
}

如果accountDictionary引用newDict并且保留计数为newDict1,则在调用 to[accountDictionary release]之前的调用[newDict copy]将导致保留计数变为 0,因此 release newDict

作为错误代码的示例,我们释放旧字典然后复制新字典:

-(void)setAccountDictionary:(NSDictionary*)newDict {
    [accountDictionary release];
    accountDictionary = [newDict copy];
}

并具有以下代码:

NSDictionary *dict = [obj accountDictionary];
[obj setAccountDictionary:dict];

这是人为的,但它在 setter 中证明了这一点,accountDictionarynewDict引用了相同的实例。如果保留计数为 1,则该[accountDictionary release]行将保留计数减少到 0,从而从内存中释放实例。 [newDict copy]现在将引用一个无效的实例。

于 2011-07-29T20:30:05.187 回答
2

Apple 在实现访问器时描述了几个概念:内存管理访问器方法
如果您可以使用 Objective-C 2.0,我会使用属性和点语法。属性是 Objective-C 2.0 中的新特性,并提供自动访问器生成。
在 .h 文件中:

@property (retain) NSDictionary* accountDictionary;

在实施中:

@synthesize accountDictionary;

Synthesize 为您的 NSDictionary 生成访问器方法。(如果您想提供自己的实现,也可以这样做)

于 2009-06-09T17:02:24.143 回答