在执行整个 init 方法之前调用 viewDidLoad
viewDidLoad is called before whole init method is executed
编辑:Xcode 6.4
的完整 code example
我有一个没有故事板的简单 iOS 应用程序。我在 AppDelegate.swift
中为 UIWindow
设置 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实现如下:
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
的 classes 中。如果你用 UIViewController
后代尝试这个相同的例子,一切正常,并且在执行 init 方法后调用 viewDidLoad
。
不保证只有在 init 方法完成后才会调用 viewDidLoad
。 viewDidLoad
在视图控制器需要加载其视图层次结构时被调用。
在内部,TabBarController
的 init 方法(通过调用 super.init)正在做一些导致视图加载的事情。
这适用于所有视图控制器。例如:如果您创建一个 UIViewController
子类并在初始化时对其 view
属性 执行任何操作,例如添加子视图,甚至只是设置 backgroundColor
属性 的视图 - 你会注意到相同的行为。
UITabBarController 的 init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?)
似乎出于某种原因调用了 viewDidLoad
。如果您在 print("viewDidLoad")
行上设置断点,您将看到调用是作为初始化序列的一部分进行的。
如果您将视图控制器更改为 UIViewController
的子类,您将看到 viewDidLoad
不是作为初始化序列的一部分被调用,而是作为调用 makeKeyAndVisible
[ 的结果=17=]
我不知道为什么 Apple 会这样编码,但我怀疑这是为了让标签栏控制器有机会在加载内容视图控制器之前进行设置。
无论如何,如果你想继承 UITabBarController
,这只是你将不得不处理的事情
发件人:http://www.andrewmonshizadeh.com/2015/02/23/uitabbarcontroller-is-different/
这应该不足为奇,但显然 UITabBarController 的行为与大多数视图控制器不同。它的生命周期可能总体上与其他视图控制器“相同”,但它执行的顺序不同。
也就是说,当您创建 UITabBarController 的子类并提供您自己的自定义初始化程序时,您会注意到 viewDidLoad 方法以一种意想不到的方式被调用。也就是说,一旦您调用 [super init](或 UITabBarController 上的其他初始化程序),它就会在初始化期间调用 loadView,然后调用您的 viewDidLoad。这可能不是您所期望的,因为大多数(所有?)其他 UIViewController 子类在初始化过程中不会实例化它们的视图。因此,如果您提供了自定义初始化程序并希望在加载视图之前进行一些设置,然后在加载视图后添加包含的视图控制器,这将破坏您的逻辑。
解决方案实际上是将设置代码从标准 viewDidLoad 方法中移出,并移至在自定义初始化程序末尾调用的特殊设置方法中。在我看来,这是一种 Apple 绝不应该放过的“代码味道”。不过,这很可能是因为 UITabBarController 需要将 UITabBar 添加到 UIViewController 的视图中,这需要该视图存在。这就是触发 loadView 的原因。
编辑:Xcode 6.4
的完整 code example我有一个没有故事板的简单 iOS 应用程序。我在 AppDelegate.swift
中为 UIWindow
设置 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实现如下:
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
的 classes 中。如果你用 UIViewController
后代尝试这个相同的例子,一切正常,并且在执行 init 方法后调用 viewDidLoad
。
不保证只有在 init 方法完成后才会调用 viewDidLoad
。 viewDidLoad
在视图控制器需要加载其视图层次结构时被调用。
在内部,TabBarController
的 init 方法(通过调用 super.init)正在做一些导致视图加载的事情。
这适用于所有视图控制器。例如:如果您创建一个 UIViewController
子类并在初始化时对其 view
属性 执行任何操作,例如添加子视图,甚至只是设置 backgroundColor
属性 的视图 - 你会注意到相同的行为。
UITabBarController 的 init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?)
似乎出于某种原因调用了 viewDidLoad
。如果您在 print("viewDidLoad")
行上设置断点,您将看到调用是作为初始化序列的一部分进行的。
如果您将视图控制器更改为 UIViewController
的子类,您将看到 viewDidLoad
不是作为初始化序列的一部分被调用,而是作为调用 makeKeyAndVisible
[ 的结果=17=]
我不知道为什么 Apple 会这样编码,但我怀疑这是为了让标签栏控制器有机会在加载内容视图控制器之前进行设置。
无论如何,如果你想继承 UITabBarController
发件人:http://www.andrewmonshizadeh.com/2015/02/23/uitabbarcontroller-is-different/
这应该不足为奇,但显然 UITabBarController 的行为与大多数视图控制器不同。它的生命周期可能总体上与其他视图控制器“相同”,但它执行的顺序不同。
也就是说,当您创建 UITabBarController 的子类并提供您自己的自定义初始化程序时,您会注意到 viewDidLoad 方法以一种意想不到的方式被调用。也就是说,一旦您调用 [super init](或 UITabBarController 上的其他初始化程序),它就会在初始化期间调用 loadView,然后调用您的 viewDidLoad。这可能不是您所期望的,因为大多数(所有?)其他 UIViewController 子类在初始化过程中不会实例化它们的视图。因此,如果您提供了自定义初始化程序并希望在加载视图之前进行一些设置,然后在加载视图后添加包含的视图控制器,这将破坏您的逻辑。
解决方案实际上是将设置代码从标准 viewDidLoad 方法中移出,并移至在自定义初始化程序末尾调用的特殊设置方法中。在我看来,这是一种 Apple 绝不应该放过的“代码味道”。不过,这很可能是因为 UITabBarController 需要将 UITabBar 添加到 UIViewController 的视图中,这需要该视图存在。这就是触发 loadView 的原因。