简体   繁体   中英

viewDidLoad is called before whole init method is executed

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.

It seems that init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) for a UITabBarController calls viewDidLoad for some reason. If you set a breakpoint on your print("viewDidLoad") line you will see that the call is made as part of the initialisation sequence.

If you change your view controller to subclass UIViewController you will see that viewDidLoad is not called as part of the initialisation sequence, but rather as a result of calling makeKeyAndVisible

I don't know why Apple coded it this way, but I suspect it is to give the tab bar controller an opportunity to set things up before the content view controllers are loaded.

Regardless, it is just something you are going to have to deal with if you want to subclass UITabBarController

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM