viewDidUnloadが使えなくなった今、ViewControllerでどうやってNSNotificationをobserveするか
表題の通りですが、ViewControllerでNSNotificationを受け取る事は非常に典型的なパターンです。
ここでは2通りの想定パターンについて簡単に紹介します。 (以下のコードはARCを利用している事を前提としています)
画面が表示されてないときはNotificationを受け取らなくて良い場合
- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didChangeHoge:) name:AKNHogeDidChangeNotification object:nil]; } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; [[NSNotificationCenter defaultCenter] removeObserver:self]; }
画面が表示されてないときにもNotificationを受け取りたい場合
こっちが本題です。
viewDidUnoadがあった頃は、viewDidUnloadとdeallocでやれば良かったのですが、そういうわけにはいかなくなりました。
また、アプリケーションの状態遷移によっては以下の様なケースがあるようで、これらに対処しなきゃなりません。
- ビューが最初にロードされる時にviewDidLoadが呼ばれる
- 他の画面に遷移
- メモリ警告発生(didReceiveMemoryWarningが呼ばれる)
- 元の画面に遷移
- viewDidLoadがまた呼ばれる
参考記事でも言及されているように、何も考慮せずにviewDidLoadでaddObserverしてdeallocでremoveObserverするだけだとNotificationを二回受け取る事になってしまうので、都合が悪いです。
なので、didReceiveMemoryWarningでremoveObserverしても良いんですけど、今後のiOSアップデートでちょっとでもイベントループが変化すると破綻するような感じで、あんまりやりたくない方針。
また、init系メソッドでaddObserverするという手もありますが、ビューのないビューコントローラでNotificationを受け取ったらクラッシュしそうだし、それを防ぐ制御コードを書くのも何だか馬鹿らしい。
などと考えた結果、以下の様にしちゃえば良いという事に気づきました。
- (void)viewDidLoad { [self addNotificationObserver]; } - (void)dealloc { [self removeNotificationObserver]; } - (void)addNotificationObserver { // 念のため先に削除する。 [self removeNotificationObserver]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didChangeHoge:) name:AKNHogeDidChangeNotification object:nil]; } - (void)removeNotificationObserver { [[NSNotificationCenter defaultCenter] removeObserver:self]; }
流石に、これが期待通りに動かなくなるようなイベントループの変更はこないでしょう。たぶん。。