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
が呼ばれてしまう。
これ知らなかったら気づけんな〜〜〜。