Objective-C二传手内存管理

时间:2009-06-09 16:46:01

标签: iphone objective-c memory-management setter

对Objective-C内存管理仍然有点困惑。我认为我的困惑源于自动释放究竟意味着什么。

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

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

顺便说一句,如果我发布theBackendResponse,我会丢失accountDictionary吗?我不认为......

4 个答案:

答案 0 :(得分:14)

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

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

    ...

    return [myObj autorelease];
}

myMethod的调用者如果想要获取返回值的所有权,则会retain返回值,否则忽略它。排除当前NSAutoreleasePool后,myObj将收到一条发布消息。如果没有其他对象拥有它(即已发送retain消息),它将被取消分配。

所有这些都在Cocoa Memory Management Programming Guide中解释。即使你已经阅读过它,总是值得另外阅读。

所以,回答你的问题:

首先,您应该发布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];
  }
}

您还必须记住dealloc方法中的release accountDictionary:

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

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

@property (copy,readwrite) NSDictionary * accountDictionary; 

向班级@interface申报。并在控制器类的@synthesize accountDictionary;块中添加@implementation指令。

答案 1 :(得分:4)

通常,一个对象或方法不应该关心另一个对象或方法如何管理内存。其他人有自动释放的事实与你无关。想到所有权的概念更简单。因此,retain和其他一些方法声明了所有权,releaseautorelease放弃了所有权。如果某个对象需要保留对另一个对象的引用,则它应该在需要时声明所有权。因此,setter方法通常会保留或复制新值并释放或自动释放旧值。

我强烈建议您阅读the Cocoa memory management guidelines。它们不是那么长或复杂,理解它们非常重要。

答案 2 :(得分:3)

在旧值是唯一拥有新值的对象的情况下,set accessor方法应始终copy / retain传入值,然后释放旧值:

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

如果accountDictionary引用newDict并且newDict的保留计数为1,则在调用[accountDictionary release]之前调用[newDict copy]会导致保留计数到0,因此释放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]现在将引用无效的实例。

答案 3 :(得分:2)

Apple在实现访问者时描述了几个概念:Memory Management Accessor Methods
如果你可以使用Objective-C 2.0,我会使用属性和点语法。 属性是Objective-C 2.0中的新功能,并提供自动访问器生成 在.h文件中:

@property (retain) NSDictionary* accountDictionary;

在实施中:

@synthesize accountDictionary;

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