最初のUIApplicationDidBecomeActiveNotificationが来ない

ビューコントローラで、

- (void)viewDidLoad {
    [super viewDidLoad];
    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
    [notificationCenter addObserver:self selector:@selector(applicationDidBecomeActive:)
        name:UIApplicationDidBecomeActiveNotification object:nil];
}

- (void)applicationDidBecomeActive:(NSNotification *)notification {
    NSLog(@"Hello!");
}

なんて書いても、iOS 8とは異なりiOS 9では最初の画面表示の際にビューコントローラの applicationDidBecomeActive メソッドは呼び出されないようです。デバッグコンソールに Hello! は表示されないです。その後、バックグラウンドから復帰するときにはきちんと呼び出されますけども。

各箇所にブレークポイントを貼って順番を調べてみると、iOS 8では初期ビューの構築が終わってからapplicationDidBecomeActiveが呼び出されてるようですが、iOS 9では仕様が変わってapplicationDidBecomeActiveが呼び出されてから初期ビューの構築が始まるようです。なので、ビューの構築時に通知先の登録してもそのイベント捕捉が空振りっていうか振り遅れの状態になっているというわけです。(あれ?、この処理順番ってiOS 6とかiOS 7に戻ってるような気がする…)

ビューコントローラのinitWithCoder:内で通知先の登録をすると、最初からapplicationDidBecomeActiveが呼び出されるようにはなりますが、結局はビュー構築の前なので本来のやりたかった用途には向かなくなっている感じですしおすし。

- (void)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
        [notificationCenter addObserver:self selector:@selector(applicationDidBecomeActive:)
            name:UIApplicationDidBecomeActiveNotification object:nil];
    }
    return self;
}

- (void)applicationDidBecomeActive:(NSNotification *)notification {
    NSLog(@"Hello!");
}

API廃止とかは明確でまだいいけど、APIは存続しているのにタイミングが異なるとか挙動が異なるとかはちょっと困ります…。

OSのバージョンを見て処理を分けたり状態フラグとか使って他のイベントと組み合わせたら回避はできるんでしょうけれど、もっとこうスマートにiOS 8とiOS 9に対応させるベストプラクティスはないもんなんですかね。

コメントを残す