swift子类*总是*必须调用super.init()

bea*_*ain 28 inheritance swift

如果我有一个swift子类:

  1. 不需要访问 self
  2. 不需要访问任何属性 self

我还需要调用super.init()子类的init()方法吗?

*注意:由于上面1和2中列出的细节,这个问题与SO上提出并回答的问题不同.

bea*_*ain 25

不,你不必.

假设您有以下课程.

class a {
    let name: String

    init() {
        name = "james"
    }
}

class b: a {
    let title: String

    override init() {
        title = "supervisor"
    }
}
Run Code Online (Sandbox Code Playgroud)

如果用实例化变量

let myVar = b()

然后,

  • override init()in b将被称为
  • 然后将调用init()ina

即使你没有明确地打电话super.init().


Chris Laettner已经在快速用户的电子邮件列表中证实了这一点.当你的超类有一个带有零参数init的指定初始化器时,它会启动.这就是为什么在从NSObject派生时不必调用super.init()的原因.

*感谢Wingzero的评论如下

  • 斯威夫特之父证实了这一点:https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20160516/001930.html:这是故意行为。当您的超类具有一个带有零参数init的指定初始化器时,它将启动。这就是为什么从NSObject派生时不必调用super.init()的原因。 (2认同)

Rik*_*les 11

来自文档:

指定的初始值设定项必须从它们的直接超类中调用指定的初始化程序.

另外,关于自动初始化器继承:

假设您为在子类中引入的任何新属性提供默认值,则适用以下两个规则:

规则1如果您的子类没有定义任何指定的初始值设定项,它会自动继承其所有超类指定的初始值设定项.

规则2如果您的子类提供了所有超类指定初始值设定项的实现 - 通过按照规则1继承它们,或者通过提供自定义实现作为其定义的一部分 - 那么它会自动继承所有超类便捷初始值设定项.

即使您的子类添加了更多便利初始值设定项,这些规则也适用.

所以你的问题的答案如下:

您的子类将始终调用超类的指定初始值设定项.如果你没有编写初始化程序并且编译器没有抱怨,那么它已经使用了自动初始化程序继承.如果您确实编写了初始化程序,但它没有显式调用相关的上游(或侧流)初始化程序,则会在初始化程序结束时自动完成.

此外,链式初始化器的工作方式是两阶段过程.在第一阶段,它从子类开始向超类开始,为任何参数分配默认值.在第二阶段,流程向后运行,从超类开始,以子类结束,参数的自定义完成并被覆盖.

这意味着您必须首先在每个init()设置变量中,然后您可以自由调用(或不调用)super.init()并运行自定义代码.因此,正如您在上面提到的那样,如果您希望超级init在开头运行,请考虑在创建变量之后的"开始":

class a {
    var name: String

    init() {
        name = "james"
        println("a")
    }
}

class b: a {
    let title: String

    override init() {
        title = "supervisor"
        super.init()
        self.name = "john"
        println("b")
    }
}

let x = b()
Run Code Online (Sandbox Code Playgroud)

这将打印a,然后b.

  • "如果你不自己做,并且编译器没有抱怨,那么它已经使用了自动初始化器继承." 如果您没有任何指定的初始值设定项,则自动初始化程序继承是继承指定的初始值设定项;如果覆盖所有超类的指定初始值设定项,则继承自定义初始值设定项.我没有看到它与隐式调用super的初始化器有什么关系. (2认同)
  • 我认为"指定的初始化程序必须从它们的直接超类中调用指定的初始化程序." 意味着不可能不显式调用超类指定的初始化程序."如果您确实编写了初始化程序,但它没有明确地调用相关的上游(或侧流)初始化程序,那么它将在初始化程序结束时自动完成." 我没有看到任何记录. (2认同)

Bin*_*ian 5

是的,指定的初始化器需要委托,所以它必须调用 super.init()。 如果你不写这一行,编译器会为你做。

所以你不必显式写super.init(...),但子类必须写,即使只是在幕后。

但是请记住,在第一阶段您需要在子类中设置属性,然后必须调用 super.init()。在第二阶段,您可以更改所有继承的属性。我认为super.init()是阶段 1 和阶段 2 之间的完美分隔符。

从文档:

安全检查2

继承的属性赋值之前,指定的初始值设定项必须委托给超类初始值设定项。如果不是,则指定的初始化器分配的新值将被超类作为其自身初始化的一部分覆盖