Objective-C:子父类型循环引用,泄漏?

时间:2010-11-14 06:17:47

标签: objective-c circular-reference

如何在这样的关系中避免内存泄漏?

@class Node;

@interface Node : NSObject {
  Node *parent;
  Node *child;
  id object;
}

-(id)initWithObject:(id)anObject;
-(id)object;
-(void)setChild:(Node *)aNode;
-(void)setParent:(Node *)aNode;

@end


@implementation Node

-(id)initWithObject:(id)anObject {
  if (self = [self init]) {
    object = [anObject retain];
  }
  return self;
}

-(id)object {
  return object;
}

-(void)setParent:(Node *)aNode {
  [parent release];
  parent = [aNode retain];
}

-(void)setChild:(Node *)aNode {
  [child release];
  child = [aNode retain];
  [child setParent:self];
}

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

@end

Node *root = [[Node alloc] initWithObject:@"foo"]; // root retain = 1
Node *child = [[Node alloc] initWithObject:@"bar"]; // child retain = 1

[root setChild:child]; // child retain = 2, root retain = 2

[root release]; // root retain = 1
[child release]; // child retain = 1

/* Leaking! */

如果您不知道前面的root应该被解除分类,您只关心您不再需要它,引用计数的方式和位置降为零?

此外,Leaks应用程序是否会将此检测为泄漏?我怀疑我可能已经被这个咬了,因为我正试图追查看似泄漏的东西,但Leaks声称我没有泄漏。由于孩子仍然引用父母,反之亦然,我敢说泄漏认为对象仍然被引用,因此不会泄漏。

2 个答案:

答案 0 :(得分:5)

根据经验,在父子关系中保留分层祖先是个坏主意。它会导致这些“保留周期”,在这些周期中,您的对象在被假设时不会被释放。对问题here有一个很好的解释,有很好的图片和建议。

答案 1 :(得分:3)

retain cycles上的苹果文档也指出了如何打破它们:在一方使用weak references,在这种情况下可能是父母。

请注意,您发布的内容还有其他问题: 考虑例如-setChild:时的aNode==childchild实例将在-retain之前取消分配,如果没有其他内容(强)引用它。

要解决这个问题:

if (aNode != child) {
    // ... same as before
}

或:

Node *tmp = child;
child = [aNode retain];
[tmp release];