TL;DR
-
UITabBarControllerを継承したカスタムクラスを作成
→TabBarControllerとする -
TabBarController()する - 落ちる(!?)
class TabBarController: UITabBarController {
var presenter: TabBarPresentable!
override func viewDidLoad() {
super.viewDidLoad()
presenter.viewDidLoad() // ここで落ちる presenterがnilだった
}
}
let tabBarController = TabBarController()
tabBarController.presenter = TabBarPresenter() // presenter後入れ
window.rootViewController = tabBarController
なぜ落ちたのか?
UITabBarControllerは初期化しただけなのにviewDidLoadが呼ばれていることが判明した。
暗黙的に強制アンラップされるpresenterが初期化されていない状態でアクセスされ、ヌルポになっていたのが原因だった。
ライフサイクルの違い
以下ではUIViewControllerとUITabBarControllerでそれぞれカスタムクラスを作成し表示してみる
①〜④はそれぞれのメソッドが呼ばれるタイミングです
UIViewController
class ViewController: UIViewController {
init() {
super.init(nibName: nil, bundle: nil) // ②
}
override func viewDidLoad() {
super.viewDidLoad() // ④
}
}
let viewController = ViewController() // ①
window.rootViewController = viewController // ③
viewDidLoadが呼ばれるのはViewControllerが画面に追加された後
UITabBarController
class TabBarController: UITabBarController {
init() {
super.init(nibName: nil, bundle: nil) // ②
}
override func viewDidLoad() {
super.viewDidLoad() // ③ ← initしただけなのに呼ばれた!!
}
}
let tabBarController = TabBarController() // ①
window.rootViewController = tabBarController // ④
初期化しただけでviewDidLoad()まで呼ばれてしまう!!
なぜこうなるのか?
Likely though, this is because the UITabBarController needs to add a UITabBar to the UIViewController’s view which requires that the view exist. Which is what fires loadView.
UITabBarControllerの初期化時にUIViewControllerにUITabBarを追加する必要があり、そのタイミングでviewにアクセスするのでloadViewが呼ばれる。
なので、初期化しただけでもviewDidLoadが呼ばれてしまう。
まとめ
UITabBarControllerは初期化時にUITabBarを追加するためviewDidLoadが呼ばれてしまう。
これ知らなかったら気づけんな〜〜〜。