Swift UINavigationController子类中必须重写的init方法

11

我目前正在为一个框架编写子类化的UINavigationController,该框架提供了一种视图控制器流(有点像UIImagePickerController)。

下面是我的一个实现示例,已经简化为尽可能简单,并可以在playground中运行。

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。(作为方便,default init方法将为您执行此操作,并为这两个方法参数指定nil)。

但是我的init(nibName nibNameOrNil:String?,bundle nibBundleOrNil:NSBundle?)覆盖被调用,来自super.init(rootViewController: viewController)初始化!
没有覆盖它,我猜UIViewController的init(nibName:bundle:)应该被调用,但不是。

我仍然无法理解为什么重写方法并调用super会使程序更加有效。在我看来,只调用super.thisMethod就覆盖一个方法完全没有意义,它只会在调用堆栈中添加一个方法调用。

我似乎缺少了有关Swift初始化方法的一些基本知识,但是我无法想出是什么。


很棒的讨论,解决了我的问题! - Alexey
1
讨论必须至少有两个人参与。我至少会有一个答案,因为我仍然不明白为什么这个方法不起作用。 - Martin
不清楚为什么在super.init(rootViewController: viewController)之后应该初始化属性,如果任何变量在super.init之前被初始化,则在super.init之后立即为空。 - Igor Palaguta
2个回答

9
这是因为Swift继承初始化器的方式。如果在当前类中没有声明任何初始化器,则编译器将从父类继承所有初始化器。但是,如果您覆盖/添加新的初始化器(并使用init(anyVar:)),则Swift不会自动从父类继承初始化器,因此它们无法从子类访问,导致运行时崩溃。
如果您对此行为背后的原因感兴趣,可以查看Intermediate Swift部分和WWDC 2014(大约在34分钟标记附近,他们正在谈论初始化器继承)。

为什么 super.init(rootViewController: homeViewController) 没有被列为仅适用于 iOS 13 的初始化程序呢? - Pedro Paulo Amorim

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接