web-dev-qa-db-ja.com

NSNotificationを使用したremoveObserver ...何が問題なのですか?

基本的に、私はある時点で(presentModalViewController:animated:を介して)view2を呼び出すview1を持っています。 view2の特定のUIButtonが押されると、view2はview1の通知メソッドを呼び出し、直後に閉じられます。通知メソッドはアラートをポップアップします。

通知メソッドは正常に機能し、適切に呼び出されます。問題は、view1が作成されるたびに(一度に1つのview1のみが存在する必要がある)、おそらく別のNSNotificationが作成されることです。なぜなら、view0(メニュー)からview1に移動すると、何度か、ビューを開いた回数と同じ回数、一連の同じアラートメッセージが通知メソッドから次々と表示されます1。

これが私のコードです、私が間違っていることを教えてください:

View1.m

-(void) viewDidLoad {
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(showAlert:) 
                                                 name:@"alert" 
                                               object:nil];
}

-(void) showAlert:(NSNotification*)notification {
    // (I've also tried to swap the removeObserver method from dealloc
    // to here, but it still fails to remove the observer.)
    // < UIAlertView code to pop up a message here. >
}

-(void) dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [super dealloc];
}

View2.m

-(IBAction) buttonWasTapped {
    [[NSNotificationCenter defaultCenter] postNotificationName:@"alert" 
                                                        object:nil];
    [self dismissModalViewControllerAnimated:YES];
}

-(void) dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [super dealloc];
}
28
Derek

-deallocの呼び出しは、ビューコントローラーが閉じられた後に自動的に行われるわけではありません。ビューコントローラーのライフタイムには、まだ「ライフ」が残っている可能性があります。その時間枠では、そのビューコントローラーはその通知に対してまだサブスクライブされています。

-viewWillDisappear:または-viewDidDisappear:でオブザーバーを削除すると、より即時に効果があります。

- (void) viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [[NSNotificationCenter defaultCenter] removeObserver:self 
                                                    name:@"alert" 
                                                  object:nil];
}
60
Alex Reynolds

オブザーバーの削除をviewWillDisappear:またはviewDidDisappear:に実装する場合、オブザーバーの追加をviewDidLoadのままにしないでください。

代わりに、オブザーバーの追加をviewWillAppear:に入れます。あなたが抱えている問題は、UIViewControllerビューにビューが表示されるとオブザーバーの削除が発生し、viewDidLoadにオブザーバーを追加したのは1回だけなので、失われた。

このアプローチは、メインビューが前面にないときに、観察したくないオブジェクトに適していることに注意してください。

また、viewDidUnloadも減価償却されていることに注意してください。

6
WhiteWabbit

deallocremoveObserver:を入れるのは問題ありません。それが呼び出されないというだけの事実は、view1が却下後に適切に解放されないことを意味します。何かがビュー1へのポインタを保持しているようです。保持サイクルを確認してください。

また、スーパーでdeallocを呼び出すべきではありません。

2
Almas Sapargali