如何在这样的关系中避免内存泄漏?
@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声称我没有泄漏。由于孩子仍然引用父母,反之亦然,我敢说泄漏认为对象仍然被引用,因此不会泄漏。
答案 0 :(得分:5)
根据经验,在父子关系中保留分层祖先是个坏主意。它会导致这些“保留周期”,在这些周期中,您的对象在被假设时不会被释放。对问题here有一个很好的解释,有很好的图片和建议。
答案 1 :(得分:3)
retain cycles上的苹果文档也指出了如何打破它们:在一方使用weak references,在这种情况下可能是父母。
请注意,您发布的内容还有其他问题:
考虑例如-setChild:
时的aNode==child
。 child
实例将在-retain
之前取消分配,如果没有其他内容(强)引用它。
要解决这个问题:
if (aNode != child) {
// ... same as before
}
或:
Node *tmp = child;
child = [aNode retain];
[tmp release];