[iOS] viewDidLoadでself.navigationControllerがnilになった。

先日、Xcode10.3でビルドしていたプロジェクトをXcode11.3にアップデートしてiOSアプリを更新しました。
更新内容は以下の通りです。

  1. Xcodeのバージョンアップ
  2. Swiftバージョンアップ(3.3 -> 5.0)
  3. 使っているOSSのアップデート(cocoapods)
  4. 対応OSバージョンアップ(iOS10〜サポート -> iOS11〜サポート)

各OSでのテスト、複数端末でのテストを行って問題なかったのでリリースしたのですが、一部の端末でアプリが起動しなくなる事がわかりました。
クラッシュログや、TestFlightでのテストの結果、一番初めに表示しているViewのviewDidLoadメソッドでself.navigationControllerがnilである事がわかりました。
現象が発生する端末やOSバージョンには傾向が見られませんが、NGな端末はアプリを再インストールしたり、OSを再起動しても状況は変わりませんでした。

問題のコード

1
2
let height = self.navigationController?.navigationBar.frame.size.height
xxx.size.height = height!   // これがダメ

そもそも、Optionalな値を!で強制的に使用しているのがNGなのですが、今までここでクラッシュした事はありませんでした。
この部分がCallされるのは、AppDelegateのdidFinishLaunchingWithOptionsでViewControllerを初期化して、NavigationConteollerに設定、windowに設定した後のはずです。
そこで、AppDelegateを確認すると以下のようになっていました。

1
2
3
4
5
:
let vc = ViewController()
let nv = NavigationController(rootViewController: vc)
window.rootViewController = nv
:

想像通り、window.rootViewControllerにNavigationControllerを設定した中でViewControllerのviewDidLoadがCallされていました。
しかしながら、viewDidLoadでnavigationControllerがnilになっています😱

調べてみると、端末によって、window.rootViewControllerに設定したら同じスレッドでそのままviewDidLoadがCallされる場合と、少ししてからCallされる場合の2パターンがあるようです。
なので、viewDidLoadの中で、初期化されている事が前提のコードがあると、それもこけます🧐

明日の為に

  1. オプショナル型を!で強制展開する時には、必ず成功する確証がある時のみにする
  2. アプリで使っているデータを初期化する場合は一番初めに行う(viewなどをinitする前)

当たり前の事ですが、今一度確認したいです。

0 件のコメント :

コメントを投稿