EDIT: Here is whole code example for Xcode 6.4
I have simple iOS application without storyboards. I set rootViewController
for UIWindow
in AppDelegate.swift
like this:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let tabBarController = TabBarController()
window = UIWindow(frame: UIScreen.mainScreen().bounds)
window?.rootViewController = tabBarController
window?.makeKeyAndVisible()
return true
}
TabBarController
class implementation is as follows:
class TabBarController: UITabBarController {
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
// Next line is called after 'viewDidLoad' method
println("init(nibName: bundle:)")
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
println("viewDidLoad")
}
}
When I run application the console output looks like this:
viewDidLoad
init(nibName: bundle:)
It means that lines after line super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
are called after viewDidLoad
method! This occurs only for classes that inherits from UITabBarController
. If you try this same example with UIViewController
descendant, everything is ok and viewDidLoad
is called after init method is executed.
You are not guaranteed to have viewDidLoad
to be called only after the init method is done. viewDidLoad
gets called when a view-controller needs to load its view hierarchy.
Internally, TabBarController
's init method (by calling super.init) is doing something which is causing the view to load.
This applies to all view-controllers. For example: if you create a UIViewController
subclass and do anything with its view
property on init, like adding a subview, or even just setting the backgroundColor
property of the view - you will notice the same behavior.
From: http://www.andrewmonshizadeh.com/2015/02/23/uitabbarcontroller-is-different/
This should come as no surprise, but apparently UITabBarController has a different behavior than most view controllers. The life cycle may overall be the “same” between it and other view controllers, but the order it executes is not.
That is, when you create a subclass of UITabBarController and provide your own custom initializer, you will notice that the viewDidLoad method is called in an unexpected way. That is, as soon as you call [super init] (or other initializer on UITabBarController), it will call loadView during that initialization which will then lead to your viewDidLoad being called. This is likely not what you would expect because most (all?) other UIViewController subclasses do not instantiate their view during the initialization process. As such, if you provided a custom initializer and expected to do some setup before the view is loaded, and then once the view is loaded add your contained view controllers, this will break your logic.
The solution is to actually move your setup code out of the standard viewDidLoad method and into a special setup method that is called at the end of your custom initializer. This strikes me as a “code smell” that Apple should have never let through. 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With