简体   繁体   English

在执行整个init方法之前调用viewDidLoad

[英]viewDidLoad is called before whole init method is executed

EDIT: Here is whole code example for Xcode 6.4 编辑:这是Xcode 6.4的完整代码示例

I have simple iOS application without storyboards. 我有简单的iOS应用程序没有故事板。 I set rootViewController for UIWindow in AppDelegate.swift like this: 我在AppDelegate.swiftUIWindow设置了rootViewController ,如下所示:

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: TabBarController类的实现如下:

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! 这意味着在viewDidLoad方法之后调用行super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)之后的行! This occurs only for classes that inherits from UITabBarController . 这仅适用于从UITabBarController继承的类。 If you try this same example with UIViewController descendant, everything is ok and viewDidLoad is called after init method is executed. 如果您使用UIViewController后代尝试相同的示例,一切正常,并且在执行init方法后调用viewDidLoad

You are not guaranteed to have viewDidLoad to be called only after the init method is done. 您不能保证只有在init方法完成后才能调用viewDidLoad viewDidLoad gets called when a view-controller needs to load its view hierarchy. 当视图控制器需要加载其视图层次结构时,将调用viewDidLoad

Internally, TabBarController 's init method (by calling super.init) is doing something which is causing the view to load. 在内部, TabBarController的init方法(通过调用super.init)正在做一些导致视图加载的事情。

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. 例如:如果您创建一个UIViewController子类并在init上对其view属性执行任何操作,例如添加子视图,甚至只是设置视图的backgroundColor属性 - 您将注意到相同的行为。

From: http://www.andrewmonshizadeh.com/2015/02/23/uitabbarcontroller-is-different/ 来自: 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. 这应该不足为奇,但显然UITabBarController的行为与大多数视图控制器不同。 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. 也就是说,当您创建UITabBarController的子类并提供自己的自定义初始化程序时,您会注意到以一种意外的方式调用了viewDidLoad方法。 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. 也就是说,只要你调用[super init](或UITabBarController上的其他初始化程序),它就会在初始化期间调用loadView,这将导致你的viewDidLoad被调用。 This is likely not what you would expect because most (all?) other UIViewController subclasses do not instantiate their view during the initialization process. 这可能不是您所期望的,因为大多数(所有?)其他UIViewController子类在初始化过程中不实例化它们的视图。 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. 解决方案是将您的设置代码实际移出标准viewDidLoad方法,并转换为在自定义初始化程序结束时调用的特殊设置方法。 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. 可能,这是因为UITabBarController需要将UITabBar添加到UIViewController的视图中,这需要视图存在。 Which is what fires loadView. 这是什么火灾loadView。

It seems that init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) for a UITabBarController calls viewDidLoad for some reason. 似乎init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?)由于某种原因调用viewDidLoad If you set a breakpoint on your print("viewDidLoad") line you will see that the call is made as part of the initialisation sequence. 如果在print("viewDidLoad")行上设置断点,您将看到该调用是作为初始化序列的一部分进行的。

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 如果将视图控制器更改为子类UIViewController您将看到viewDidLoad未作为初始化序列的一部分被调用,而是作为调用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. 我不知道为什么Apple会这样编码,但我怀疑它是在标签栏控制器有机会在内容视图控制器加载之前进行设置的。

Regardless, it is just something you are going to have to deal with if you want to subclass UITabBarController 无论如何,如果你想要UITabBarController ,它只是你要处理的东西

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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