iOS7,8,9のアプリケーションライフサイクル

以前に作ったアプリがiOS9でうまく動かないという連絡を受けたので調査した結果、アプリケーションのライフサイクルが変更されたことによりイベントトリガと描画の関係が前後するというしょぼいミスをしていました。
悔しいので変化をまとめました。

具体的な問題の原因となった箇所はこちら。詳細は下のライフサイクルを見たらわかります。

-[AppDelegate applicationDidBecomeActive:]

検証したアプリの画面構成

  1. UINavigationController
  2. FirstViewController
  3. SecondViewController(FirstViewController.navigationControllerにpushされる)

iOS7 (7.1.2

// 起動
-[FirstViewController awakeFromNib]
-[AppDelegate application:willFinishLaunchingWithOptions:]
-[AppDelegate application:didFinishLaunchingWithOptions:]
-[FirstViewController viewDidLoad]
-[FirstViewController viewWillAppear:]
-[FirstViewController viewWillLayoutSubviews]
-[FirstViewController viewDidLayoutSubviews]
-[AppDelegate applicationDidBecomeActive:]
-[FirstViewController viewDidAppear:]

// ホームボタンをタップ、バックグラウンドへ
-[AppDelegate applicationWillResignActive:]
-[AppDelegate applicationDidEnterBackground:]

// フォアグラウンドへ
-[AppDelegate applicationWillEnterForeground:]
-[AppDelegate applicationDidBecomeActive:]

// SecondViewControllerをpushする
-[SecondViewController awakeFromNib]
-[SecondViewController viewDidLoad]
-[FirstViewController viewWillDisappear:]
-[SecondViewController viewWillAppear:]
-[SecondViewController viewWillLayoutSubviews]
-[SecondViewController viewDidLayoutSubviews]
-[FirstViewController viewDidDisappear:]
-[SecondViewController viewDidAppear:]
-[SecondViewController viewWillLayoutSubviews]
-[SecondViewController viewDidLayoutSubviews]

// SecondViewControllerをpopする
-[SecondViewController viewWillDisappear:]
-[FirstViewController viewWillAppear:]
-[FirstViewController viewWillLayoutSubviews]
-[FirstViewController viewDidLayoutSubviews]
-[SecondViewController viewDidDisappear:]
-[FirstViewController viewDidAppear:]
-[SecondViewController dealloc]
-[FirstViewController viewWillLayoutSubviews]
-[FirstViewController viewDidLayoutSubviews]

iOS8 (8.4.1

// 起動
-[FirstViewController awakeFromNib]
-[AppDelegate application:willFinishLaunchingWithOptions:]
-[AppDelegate application:didFinishLaunchingWithOptions:]
-[FirstViewController viewDidLoad]
-[FirstViewController viewWillAppear:]
-[FirstViewController viewWillLayoutSubviews]
-[FirstViewController viewDidLayoutSubviews]
-[FirstViewController viewWillLayoutSubviews]
-[FirstViewController viewDidLayoutSubviews]
-[FirstViewController viewDidAppear:]
-[AppDelegate applicationDidBecomeActive:]

// ホームボタンをタップ、バックグラウンドへ
-[AppDelegate applicationWillResignActive:]
-[AppDelegate applicationDidEnterBackground:]

// フォアグラウンドへ
-[AppDelegate applicationWillEnterForeground:]
-[AppDelegate applicationDidBecomeActive:]

// SecondViewControllerをpushする
-[SecondViewController awakeFromNib]
-[SecondViewController viewDidLoad]
-[FirstViewController viewWillDisappear:]
-[SecondViewController viewWillAppear:]
-[SecondViewController viewWillLayoutSubviews]
-[SecondViewController viewDidLayoutSubviews]
-[FirstViewController viewWillLayoutSubviews]
-[FirstViewController viewDidLayoutSubviews]
-[FirstViewController viewDidDisappear:]
-[SecondViewController viewDidAppear:]
-[SecondViewController viewWillLayoutSubviews]
-[SecondViewController viewDidLayoutSubviews]

// SecondViewControllerをpopする
-[SecondViewController viewWillDisappear:]
-[FirstViewController viewWillAppear:]
-[SecondViewController viewWillLayoutSubviews]
-[SecondViewController viewDidLayoutSubviews]
-[FirstViewController viewWillLayoutSubviews]
-[FirstViewController viewDidLayoutSubviews]
-[SecondViewController viewDidDisappear:]
-[FirstViewController viewDidAppear:]
-[SecondViewController dealloc]
-[FirstViewController viewWillLayoutSubviews]
-[FirstViewController viewDidLayoutSubviews]

iOS9 (9.0

// 起動
-[FirstViewController awakeFromNib]
-[AppDelegate application:willFinishLaunchingWithOptions:]
-[AppDelegate application:didFinishLaunchingWithOptions:]
-[AppDelegate applicationDidBecomeActive:]
-[FirstViewController viewDidLoad]
-[FirstViewController viewWillAppear:]
-[FirstViewController viewWillLayoutSubviews]
-[FirstViewController viewDidLayoutSubviews]
-[FirstViewController viewWillLayoutSubviews]
-[FirstViewController viewDidLayoutSubviews]
-[FirstViewController viewDidAppear:]

// ホームボタンをタップ、バックグラウンドへ
-[AppDelegate applicationWillResignActive:]
-[AppDelegate applicationDidEnterBackground:]

// フォアグラウンドへ
-[AppDelegate applicationWillEnterForeground:]
-[AppDelegate applicationDidBecomeActive:]

// SecondViewControllerをpushする
-[SecondViewController awakeFromNib]
-[FirstViewController viewWillDisappear:]
-[SecondViewController viewDidLoad]
-[SecondViewController viewWillAppear:]
-[SecondViewController viewWillLayoutSubviews]
-[SecondViewController viewDidLayoutSubviews]
-[FirstViewController viewWillLayoutSubviews]
-[FirstViewController viewDidLayoutSubviews]
-[FirstViewController viewDidDisappear:]
-[SecondViewController viewDidAppear:]
-[SecondViewController viewWillLayoutSubviews]
-[SecondViewController viewDidLayoutSubviews]

// SecondViewControllerをpopする
-[SecondViewController viewWillDisappear:]
-[FirstViewController viewWillAppear:]
-[SecondViewController viewWillLayoutSubviews]
-[SecondViewController viewDidLayoutSubviews]
-[FirstViewController viewWillLayoutSubviews]
-[FirstViewController viewDidLayoutSubviews]
-[SecondViewController viewDidDisappear:]
-[FirstViewController viewDidAppear:]
-[SecondViewController dealloc]
-[FirstViewController viewWillLayoutSubviews]
-[FirstViewController viewDidLayoutSubviews]

さいごに

検証に使用したマクロはNSLog(@"%s", __PRETTY_FUNCTION__)です。

UINavigationControllerを使う場合と使わない場合で、[UIViewController viewWillLayoutSubviews] [UIViewController viewDidLayoutSubviews] の呼ばれ方が変わります。
UINavigationControllerを使わないパターンは自分のアプリ設計的にありえないので考慮していません。