20

私はiPhoneアプリケーションに取り組んでいます。Rowclassの多数のオブジェクトを解放する必要があるclassのオブジェクトがありBlockます。EveryBlockには現在、 class のインスタンス変数を保持するプロパティがありますRow

@interface Block : UIImageView {
  Row *yCoord;
}
@property (nonatomic,retain) Row *yCoord;
@end

Everyには、これらのブロックRowが含まれています。NSMutableArray

@interface Row : NSObject {
    NSMutableArray *blocks;
}
-(void)addBlock:(Block*)aBlock;
@end

@implementation Row
-(void)addBlock:(Block*)aBlock {
    [blocks addObject:aBlock];
    aBlock.yCoord = self;
}
@end

これが循環参照であることを理解しています。Apple のドキュメントには、循環参照を持つオブジェクトの割り当てを解除するには、強参照 (retain プロパティ) の代わりに弱参照が必要であると記載されていますが、それは実行されておらず、正確にどのように行っているかを説明していません。行内のすべてのブロックと行自体を同時に解放および解放する予定です。各ブロック内で「親」行への弱い参照を設定するにはどうすればよいですか?

4

4 に答える 4

19

編集:質問者がガベージ コレクションを使用していないことを明らかにしたので (iPhone は現在サポートしていません)、私のアドバイスは、デリゲートの場合と同様に、オブジェクトの 1 つだけが他のオブジェクトを保持することによってサイクルを回避することです。プロパティを使用する場合は、「retain」ではなく「assign」を使用してこれを実現します。例えば:

@property (nonatomic,assign) Row *yCoord;

私の回答の残りの部分は、Objective-C 2.0 と GC に関する「弱い参照」に関連しています。


ガベージ コレクション (10.5 以降) を使用している場合、変数宣言の前に__weak. その変数に割り当てると、GC (有効な場合) は参照を追跡し、参照先オブジェクトへのすべての強い参照がなくなると自動的にゼロにします。(GC が有効になっていない場合、__weak属性は無視されます。)

したがって、次のように、上記の回答を安全に変更して、ガベージ コレクション (現在は 10.5 以降、おそらくいつかは iPhone で) をより適切に処理できます: (関連する Apple ドキュメントを参照してください。)

@property (nonatomic,assign) __weak Row *yCoord;

Chris Hansonの言葉を引用すると (より詳細な情報が見つかります):

「インスタンス変数宣言の前に を付けることで、__weakそれがオブジェクトへの唯一の参照である場合、オブジェクトを収集可能と見なす必要があることをガベージ コレクターに伝えます。」

「オブジェクトへの弱い参照がない場合」と言って、それを明確にします。最後の強参照が削除されるとすぐに、オブジェクトが収集され、すべての弱参照が自動的にゼロになります。

注:これは弱参照の作成とは直接関係ありませんが、属性もあり__strongますが、Objective-C オブジェクト変数は既定で強参照であるため、通常、構造体やプリミティブなどへの生の C ポインターにのみ使用されます。ガベージ コレクターは根として扱われず、強力であると宣言しない場合、あなたの下から収集されます。( の欠如は__weakリテイン サイクルとメモリ リークを引き起こす可能性がありますが、 の欠如は__strongメモリ ストンピングや、非決定論的に発生する非常に奇妙で潜行性のバグを引き起こす可能性があり、追跡が非常に困難になる可能性があります。)

于 2009-07-02T04:47:05.740 に答える
4

弱い参照は単なる割り当てです (ワームの完全に別の缶であるガベージ コレクションについて話している場合を除きますが、保持サイクルに悩まされることはありません)。

通常、Cocoa では、オブジェクトを (NSMutableArray に含めることによって)Row保持しますが、保持せず、それぞれが (「割り当て」プロパティを使用して) ivar に格納するだけです。BlockBlockRow

Row割り当てを解除する前にそれぞれを慎重に解放する限りBlock(つまり、dealloc他の誰もブロックへのポインタを持っていない限り、ブロックを解放する NSMutableArray を解放する必要があります)、すべてが適切に割り当て解除されます。

次のように、配列からエントリを削除する前に、ブロックからの行参照をゼロにする予防策を講じることもできます。

- (void) dealloc {
    for (Block* b in _blocks) {
        b.row = nil;
    }
    [_blocks release];
    [super dealloc];
}

ここで、_blocks は、blocks プロパティによって参照される ivar です。

于 2009-07-02T04:51:33.163 に答える
3

弱い参照を作成するために割り当てを使用することは、マルチスレッド システムでは安全ではない可能性があります。

幸いなことに、これはしばしば階層の問題であり、弱参照を含むオブジェクトは、参照先オブジェクトの存続期間中、参照先のオブジェクトのみを気にします。これは、上位 <-> 下位関係の通常の状況です。

OPのコメントのケースはこれに対応していると思います.Row = Superior、Block = Subordinate.

この場合、ハンドルを使用して、部下から上司を参照します。

// Superior.h

@class Superior;

@interface SuperiorHandle : NSObject {
    @private
        Superior* superior_;
}

// note the deliberate avoidance of "nonatomic"
@property (readonly) Superior *superior;

@end

@interface Superior : NSObject {
    @private
        SuperiorHandle *handle_;
        // add one or more references to Subordinate instances
}

// note the deliberate avoidance of "nonatomic"
@property (readonly) SuperiorHandle *handle;

@end


// Superior.m

#import "Superior.h"

@implementation SuperiorHandle

@synthesize
    superior = superior_;

- (id)initWithSuperior:(Superior *)superior {
    if ((self = [super init])) {
        superior_ = superior; // weak reference
    }
}

- (void)invalidate {
    @synchronized (self) {
        superior_ = nil;
    }
}

- (Superior *)superior {
    @synchronized (self) {
        // retain and autorelease is required to prevent dealloc before we're ready, thanks to AndroidDev for pointing out this mistake
        return [[superior_ retain] autorelease];
    }
}

@end

@implementation Superior

@synthesize
    handle = handle_;

- (id)init {
    if ((self = [super init])) {
        handle_ = [[SuperiorHandle alloc] initWithSuperior:self];
    }
    return self;
}

- (void)dealloc {
    [handle_ invalidate];
    [handle_ release];

    [super dealloc];
}

@end


// Subordinate.h

@class Superior;
@class SuperiorHandle;

@interface Subordinate : NSObject {
    @private
        SuperiorHandle *superior_handle_;
}

@property (readonly) Superior *superior;

@end


// Subordinate.m

#import "Subordinate.h"

#import "Superior.h"

@implementation Subordinate

// no synthesize this time, superior's implementation is special

- (id)initWithSuperior:(Superior *)superior {
    if ((self = [super init])) {
        superior_handle_ = [superior.handle retain];
    }
    return self;
}

- (void)dealloc {
    [superior_handle_ release];

    [super dealloc];
}

- (Superior *)superior { 
    @synchronized (superior_handle_) {
        return superior_handle_.superior; 
    }
}

@end

いくつかの利点:

  1. スレッドセーフです。Subordinate に含まれる弱い参照を無効なポインターにする方法はありません。nil になるかもしれませんが、それで問題ありません。
  2. 埋め込まれた弱い参照について知る必要があるのは、オブジェクト自体だけです。他のすべてのオブジェクトは、上位への通常の参照があるかのように下位を扱うことができます。
于 2011-05-17T21:24:28.783 に答える