Swift UINavigationController子类中的强制init覆盖

时间:2016-06-25 13:19:10

标签: swift override

我目前正在为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方法的要点,但我无法弄清楚是什么。

2 个答案:

答案 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)
    }
}