我目前正在为UINavigationController
子类化一个为视图控制器流提供服务的框架(在某种程度上,像UIImagePickerController
那样做)
以下是我的实施示例,简化为尽可能简单,可以在游乐场中运行。
import UIKit
public class MyNavigationController: UINavigationController {
public var anyVar: Int?
public init(anyVar: Int) {
let viewController = UIViewController()
super.init(rootViewController: viewController)
self.anyVar = anyVar
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
let navigationController = MyNavigationController(anyVar: 42)
最后一行崩溃,EXC_BAD_INSTRUCTION
。当我在Xcode中运行时,它告诉我在运行时,init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?)
丢失了。
如果我覆盖方法:
public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
......一切运作良好:你可以尝试自己的游乐场。
我无法理解为什么。这对我来说听起来不合逻辑。
UIViewController
文档说:
如果你是UIViewController的子类,你必须调用它的超级实现 方法,即使您没有使用NIB。 (为方便起见,默认的init方法会为您执行此操作, 并为这两个方法参数指定nil。)
但我的init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?)
覆盖从super.init(rootViewController: viewController)
初始化开始被调用!
如果不覆盖它,我想应该调用UIViewController的init(nibName:bundle:)
,但不是。
我仍然无法理解为什么重写方法并调用super
会使程序更好地运行。 IMO,在仅调用super.thisMethod
时覆盖方法完全没用,它只在调用堆栈中添加方法调用。
我必须遗漏一些关于Swift init方法的要点,但我无法弄清楚是什么。
答案 0 :(得分:4)
这是因为Swift继承初始化器的方式。如果您未在当前类中声明任何初始值设定项,则编译器将从父类继承所有初始值设定项。但是如果你覆盖/添加新的初始化器(并且用init(anyVar:)
来做),Swift将不会自动从父类继承初始化器,因此无法从子类访问它们,这会导致运行时崩溃。
如果您对此行为之外的原因感兴趣,可以查看Intermediate Swift部分和2014年WWDC(大约34分钟左右,他们正在讨论初始化程序继承)
答案 1 :(得分:0)
您可以在启动超类
后分配根public class MyNavigationController: UINavigationController {
public var anyVar: Int?
public init(anyVar: Int) {
super.init(nibName: nil, bundle: nil)
viewControllers = [UIViewController()]
self.anyVar = anyVar
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}