DarkMode 対応したらアプリ起動時にクラッシュするようになってしまった
事象
DarkMode 対応したら、アプリ起動時にクラッシュするようになってしまった。
クラッシュ内容は、アプリ起動時に表示する VC である TopViewController の viewDidLoad()
内での EXC_BREAKPOINT
で、 iOS 13 系の端末のみで発生する模様。
スタックトレースを一部抜粋するとこんな感じ。
Crashed: com.apple.main-thread 0 MyApp 0x10022293c TopViewController.viewDidLoad() + 112 (TopViewController.swift:112) 1 MyApp 0x100222fb8 @objc TopViewController.viewDidLoad() (<compiler-generated>) 2 UIKitCore 0x1ba9b00e4 -[UIViewController _sendViewDidLoadWithAppearanceProxyObjectTaggingEnabled] + 104 3 UIKitCore 0x1ba9b4d18 -[UIViewController loadViewIfRequired] + 952 4 UIKitCore 0x1ba9b5104 -[UIViewController view] + 32
調査 & 対応
このクラッシュ、特定のユーザは 100% 起こるようなのにも関わらず、自分の手元では全く再現できないので調査に大苦戦した。ちなみに、クラッシュが生じるようになったバージョンでは viewDidLoad()
内のコードは一切変えていなかった。
再現できてしまえば直したも同然なので、端末の設定をいろいろ変えて再現できるか確認した。
- アクセシビリティ
- 画面表示設定と明るさ
の各項目をいろいろ変えてみたけど再現できず...
再現できなければ、いろいろ試してリリースして様子を見るしかないので、いろいろコードを修正してリリースしてみた。 しかし、一向に直らず。
コードというよりもプロジェクトの設定が悪いんじゃないかと思っていろいろ確認していたら、アプリの Main Target の General の Main Interface
に、アプリ起動時に表示する VC である TopViewController が設定してあった。
この項目は Info.plist の UIMainStoryboardFile
として設定されるようで、Apple のドキュメントを見てみると
When this key is present, the main storyboard file is loaded automatically at launch time and its initial view controller installed in the app’s window.
iOS Keys
と書いてあった。
自分のアプリでは、以下のように AppDelegate の application(_:,didFinishLaunchingWithOptions:)
内で TopViewController を初期化して window.rootViewController
にセットしていたので、 Main Interface
の指定と合わせると二重に画面の初期化処理が走ってしまっているみたいだった。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { window?.rootViewController = TopViewController() window?.makeKeyAndVisible()
これはこれで問題なので、 Main Interface
での指定は削除(何も設定しないように)して、以下のように初期化処理をコードに集約させた。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { window = UIWindow(frame: UIScreen.main.bounds) window?.rootViewController = TopViewController() window?.makeKeyAndVisible()
このバージョンをリリースしてみたところ、なんと、無事クラッシュが治まっていた。
UIKit のコードは読めないので詳細な理由はわからないけど、DarkMode 対応することで View の初期化処理がいろいろ変わるとかそんな感じだと思う。
とにかく、めちゃくちゃ安心した。
まとめ
今までは問題なかった実装や設定も、 iOS や SDK のアップデート等で動かなくなってしまうことがあるので、Apple のドキュメントをちゃんと読んで実装するの大事。