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

时间:2015-07-18 09:58:31

标签: ios swift uitabbarcontroller init viewdidload

编辑:这是Xcode 6.4的全部code example

我有简单的iOS应用程序,没有故事板。我在rootViewController中为UIWindow设置了AppDelegate.swift,如下所示:

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 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")
    }

}

当我运行应用程序时,控制台输出如下所示:

viewDidLoad
init(nibName: bundle:)

这意味着在super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)方法之后调用行viewDidLoad之后的行!这仅适用于继承自UITabBarController的类。如果您使用UIViewController后代尝试相同的示例,则一切正常,并且在执行init方法后调用viewDidLoad

3 个答案:

答案 0 :(得分:9)

只有在init方法完成后才能保证只调用viewDidLoad。当视图控制器需要加载其视图层次结构时,将调用viewDidLoad

在内部,TabBarController的init方法(通过调用super.init)正在做一些导致视图加载的事情。

这适用于所有视图控制器。例如:如果您创建一个UIViewController子类并在init上执行其view属性,例如添加子视图,甚至只是设置视图的backgroundColor属性 - 您会注意到同样的行为。

答案 1 :(得分:6)

来自:http://www.andrewmonshizadeh.com/2015/02/23/uitabbarcontroller-is-different/

这应该不足为奇,但显然UITabBarController的行为与大多数视图控制器不同。生命周期在整个生命周期和其他视图控制器之间可能总体上是“相同的”,但它执行的顺序不是。

也就是说,当您创建UITabBarController的子类并提供自己的自定义初始化程序时,您会注意到以一种意外的方式调用了viewDidLoad方法。也就是说,只要你调用[super init](或UITabBarController上的其他初始化程序),它就会在初始化期间调用loadView,这将导致你的viewDidLoad被调用。这可能不是您所期望的,因为大多数(所有?)其他UIViewController子类在初始化过程中不实例化它们的视图。因此,如果您提供了自定义初始化程序并希望在加载视图之前进行一些设置,然后在加载视图后添加包含的视图控制器,这将破坏您的逻辑。

解决方案是将您的设置代码实际移出标准viewDidLoad方法,并转换为在自定义初始化程序结束时调用的特殊设置方法。这让我觉得苹果应该永远不会忘记“代码味道”。可能,这是因为UITabBarController需要将UITabBar添加到UIViewController的视图中,这需要视图存在。这是什么导致loadView。

答案 2 :(得分:1)

由于某些原因,UITabBarController似乎init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?)调用viewDidLoad。如果在print("viewDidLoad")行设置断点,您将看到该调用是初始化序列的一部分。

如果将视图控制器更改为子类UIViewController,您将看到viewDidLoad未作为初始化序列的一部分调用,而是作为调用makeKeyAndVisible的结果

我不知道为什么Apple会这样编码,但我怀疑它是在标签栏控制器有机会在内容视图控制器加载之前进行设置的。

无论如何,如果你想要继承UITabBarController

,这只是你必须要处理的事情。