1

他の場所でブロードキャストされる通知にサブスクライブしているView Controllerがあります。これは、子の割り当てが解除されたときに実行する必要があるいくつかのクリーンアップを含む大きなオブジェクト グラフの一部です。しかし、dealloc が子の 1 つ (ARC 環境) で呼び出されることはありませんでした。これは、(私が理解している場合) どこかに何かがまだ保持されていることを意味し、VC が破棄されても ARC は決して dealloc されません。問題のあるコードを次の 2 行までたどりました。最初のバージョンでは、VC と子が完全に解放されることはありません。2 番目のバージョンでは問題なく動作し、この VC が破棄されるとすべてが解放されます。

私の質問はなぜですか?ARC では、この追加の NSArray が適切にリリースされない理由がわかりません。

うまくいけば、これで十分なコードです。必要に応じてさらに投稿できます。

VC (および子など) が完全に解放されないバージョンは次のとおりです。

// Subscribe to notifications that the number of trackables has changed
[[NSNotificationCenter defaultCenter] addObserverForName:kUpdatedNumberofTrackables object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
    if ([note.object isKindOfClass:[NSArray class]]) {
        NSArray *activeTrackableNames = note.object; // <-- offending line
        [self trackableUpdate:activeTrackableNames]; // <-- offending line
    } else {
        NSLog(@"Observer error. Object is not NSArray");
    }
}];

しかし、次のようにすると、ビューがアンロードされたときにすべてが適切に解放されるため、子 VC で dealloc が呼び出されます。

// Subscribe to notifications that the number of trackables has changed
[[NSNotificationCenter defaultCenter] addObserverForName:kUpdatedNumberofTrackables object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
    if ([note.object isKindOfClass:[NSArray class]]) {
        [self trackableUpdate:note.object]; // <-- seems to work
    } else {
        NSLog(@"Observer error. Object is not NSArray");
    }
}];

この VC で役割を果たしている可能性がある (?) 他のいくつかの関連メソッド:

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    self.trackablesVisible_private = nil;
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

#pragma mark - Target Handling
-(void)trackableUpdate:(NSArray *)trackablesArray {
    NSLog(@"Trackable Changed");
    if (([trackablesArray count] > 0) && [self.delegate respondsToSelector:@selector(foundValidTargets:)]) {
        [delegate foundValidTargets:trackablesArray];
    }
    self.trackablesVisible_private = trackablesArray;
}

ここで何が起こっているのかわかりません。誰かが私を啓発してもらえますか?

ありがとう!

編集:

返信で指摘されているように、問題の一部はselfブロックで弱点を使用しなかったことによる保持サイクルですが、通知センターを使用しているため、ここで別の問題が発生しているようです. 解決策は次のとおりです:ブロックからモーダル ビューを閉じるときに、Dealloc が実行されない

私の最終的な作業コードは次のとおりです。

@interface

__weak id observer;

loadView

__weak ThisViewController *blockSelf = self; // Avoids retain cycle
observer = [[NSNotificationCenter defaultCenter] addObserverForName:kUpdatedNumberofTrackables object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
    if ([note.object isKindOfClass:[NSArray class]]) {
        ThisViewController *strongSelf = blockSelf; // Avoids retain cycle
        NSArray *activeTrackableNames = note.object;
        [strongSelf trackableUpdate:activeTrackableNames];
    } else {
        NSLog(@"Observer error. Object is not NSArray");
    }
}];

そしてviewWillDisappear

[[NSNotificationCenter defaultCenter] removeObserver:observer];

単に を削除するのではなく、返されたオブザーバー オブジェクトを保存する必要がある理由をまだ完全には理解していませんselfが、これは機能します。

4

1 に答える 1

2

ブロックに保持サイクルがあります...これがあなたが望むものです

__weak MyViewControllerName *bSelf = self;
// Subscribe to notifications that the number of trackables has changed
[[NSNotificationCenter defaultCenter] addObserverForName:kUpdatedNumberofTrackables object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
    if ([note.object isKindOfClass:[NSArray class]]) {
        **NSArray *activeTrackableNames = note.object;
        [bSelf trackableUpdate:activeTrackableNames];**
    } else {
        NSLog(@"Observer error. Object is not NSArray");
    }
}];

ブロックと保持サイクルの詳細については、http://zearfoss.wordpress.com/2012/05/11/a-quick-gotcha-about-blocks/をご覧ください。

于 2013-04-19T22:11:12.813 に答える