web-dev-qa-db-ja.com

UIViewControllerのNSNotificationCenterへのオブザーバーの追加と削除

さまざまなApple例(たとえば 音楽の追加 )を見ると、NSNotificationCenterのデフォルトのviewDidLoadにオブザーバーが追加されています。 、次にそれらをdeallocで削除します。viewDidLoaddeallocを呼び出さずに複数回呼び出すことができるため、これは危険なようです。これにより、同じオブザーバーが複数回追加され、ハンドラーが発生します。複数回呼び出されます。

これに対する解決策は、viewDidUnloadのオブザーバーも削除することですが、これは、同じオブザーバーがdeallocでもう一度削除される可能性があることを意味し、潜在的な問題のようです。

何が足りないのですか?

17
Undistraction

正しい方法で通知を削除することについては、多くの議論があります。例えば:

viewWillDisappear(またはviewDidDisappear)およびviewDidUnloadライフサイクルメソッドでオブザーバーを削除することをお勧めします。 (注:viewDidUnloadは非推奨であり、iOS6以降では実装しないでください。 iOS 6 --viewDidUnloadはdidReceiveMemoryWarningに移行します)を参照してください。 ?

重要な注意:

viewDidUnloadが呼び出される保証はありません。これは標準のライフサイクルメソッドではありません。

From Apple doc:

viewDidUnloadメモリ不足の状態が発生し、現在のView Controllerのビューが不要な場合、システムはそれらのビューをメモリから削除することを選択する場合があります。このメソッドは、ビューコントローラのビューが解放された後に呼び出され、最終的なクリーンアップを実行するチャンスです。

代わりに、そのレシーバーの参照数がゼロの場合は常にdeallocが呼び出されます。

それが役に立てば幸い。

編集

完全を期すために、 avoid-nsnotification-removeobserver の方法に関するこのリンクを参照してください。リンクは、オブザーバーを削除するためのいくつかの有用なガイドラインを提供します(コメントも参照してください)。 viewDidAppearviewDidDisappearは多くのアプリケーションで常に正しく呼び出されるとは限らないため、作成者はviewWillAppear/viewWillDisappearメソッドでこれを行います。それはあなたの選択です。

オブザーバーを正しい方法で確実に削除したい場合は、deallocメソッドで登録を解除するか、2番目のコメントで書いたようにビューが完全にアンロードされたときに。ただし、deallocが将来呼び出されることを確認してください。言い換えると、すでに述べたように、他のオブジェクトが参照しているためにコントローラーが存続し続けると、メソッドが呼び出されることはありません。この場合、コントローラーは引き続き通知を受信します。

24
Lorenzo B

最近このページに出くわした人々にとって、オブザーバーの削除はもう必要ないかもしれません。 addObserver(_:selector:name:object:) docs の「Discussion」セクションは次のように述べています。

アプリがiOS9.0以降またはmacOS10.11以降を対象としている場合、そのdeallocメソッドでオブザーバーの登録を解除する必要はありません。それ以外の場合は、オブザーバーまたはこのメソッドに渡されたオブジェクトの割り当てが解除される前に、removeObserver(_:name:object:)を呼び出す必要があります。

2
Cem Schemel
- (void)viewWillAppear:(BOOL)animated
{
   [super viewWillAppear:animated];
   [[NSNotificationCenter defaultCenter] addObserver:self .........]
}

- (void)viewWillDisappear:(BOOL)animated
{
   [super viewWillDisappear:animated];
   [[NSNotificationCenter defaultCenter] removeObserver:self .........];
}
2
Darshit Shah

なぜあなたはviewWillAppear/viewDidDisappearでそれをしないのですか?とにかくビューが表示されているときにのみ通知を気にしますよね?

1
mprivat

ViewWillAppearでObserverを追加し、viewWillDisappearでObserverを削除できます。ただし、viewWillAppearは何度も呼び出される場合があります。したがって、最初に通知を削除してから、addObserverを削除できます。

 -(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:YES];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"UIKeyboardWillShowNotification" object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"UIKeyboardWillHideNotification" object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillShow:)name:@"UIKeyboardWillShowNotification"object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillHide:)name:@"UIKeyboardWillHideNotification"object:nil];
 }

 -(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:YES];
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"UIKeyboardWillShowNotification" object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"UIKeyboardWillHideNotification" object:nil];
 }
0
Sola Zhou