他の場所でブロードキャストされる通知にサブスクライブしている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
が、これは機能します。