3

このような関係でメモリ リークを回避するにはどうすればよいでしょうか。

@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 はオブジェクトがまだ参照されていると見なし、したがってリークしていないと思います。

4

2 に答える 2

5

経験則として、親子関係で階層的な祖先を保持することは悪い考えです。これにより、これらの「保持サイクル」が発生し、オブジェクトが想定されているときにオブジェクトの割り当てが解除されなくなります。素敵な写真とアドバイスでここに問題の優れた説明があります。

于 2010-11-14T06:30:00.810 に答える
3

リテイン サイクルに関する Apple のドキュメントでは、それらを破る方法も示されています。この場合は、おそらく親に対して、片側で弱参照を使用します。

あなたが投稿したものには他にも問題があることに注意して-setChild:くださいaNode==childchildインスタンスへ-retainの (強い) 参照が他に何も保持されていない場合、インスタンスは の前に割り当て解除されます。

それを修正するには、次のいずれかを使用します。

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

また:

Node *tmp = child;
child = [aNode retain];
[tmp release];
于 2010-11-14T06:45:04.333 に答える