如果我有一个快速的子类:
self
self
我还需要在子类的super.init()
方法中调用init()
吗?
*注意:由于上面1和2中列出的具体细节,这个问题与询问和回答here on SO的问题不同。
答案 0 :(得分:21)
不,你不必。
假设您有以下课程。
class a {
let name: String
init() {
name = "james"
}
}
class b: a {
let title: String
override init() {
title = "supervisor"
}
}
如果使用
实例化变量 let myVar = b()
然后,
override init()
中的b
称为init()
中的a
将被称为即使你没有明确地拨打super.init()
。
Chris Laettner已经在快速用户的电子邮件列表中证实了这一点。 当你的超类有一个带有零参数init的指定初始化器时,它会启动。这就是在从NSObject派生时不必调用super.init()的原因。
*感谢Wingzero的评论
答案 1 :(得分:10)
来自文档:
指定的初始值设定项必须从它们的直接超类中调用指定的初始化程序。
另外,关于自动初始化器继承:
假设您为任何新属性提供默认值 在子类中引入,适用以下两个规则:
规则1 如果您的子类未定义任何指定的初始值设定项,则为 自动继承其所有超类指定的初始化器。
规则2 如果您的子类提供了所有子类的实现 超类指定初始化程序 - 通过按照继承它们 规则1,或通过提供自定义实现作为其一部分 定义 - 然后它自动继承所有的超类 便利初始化者。
即使您的子类增加了更多便利,这些规则也适用 初始化。
所以你的问题的答案如下:
您的子类将始终调用超类的指定初始值设定项。如果您没有编写初始化程序并且编译器没有抱怨,那么它已经使用了自动初始化程序继承。如果您确实编写了初始化程序但它没有明确调用相关的上游(或侧流)初始化程序,那么它将在初始化程序结束时自动完成。
此外,链式初始化器的工作方式是两阶段过程。在第一阶段,它从子类开始向超类开始,为任何参数分配默认值。在第二阶段,流程向后运行,从超类开始,以子类结束,参数的自定义完成并被覆盖。
这意味着您必须首先在每个init()
设置变量,然后您可以自由调用(或不调用)super.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()
这将打印a,然后b。
答案 2 :(得分:4)
是指定的初始值设定项需要委托,因此必须调用super.init()。 如果您不编写该行,编译器将为您执行此操作。
所以你不必明确地写super.init(...)
,但子类必须,即使只是幕后。
但请记住,在第一阶段,您需要在子类中设置属性,然后必须调用super.init()。在第二阶段,您可以更改所有继承的属性。我认为super.init()
是第1阶段和第2阶段之间的完美分隔符。
来自文档:
安全检查2
在为继承的属性赋值之前,指定的初始值设定项必须将委托给超类初始值设定项。如果没有,指定初始化程序分配的新值将被超类覆盖,作为其自身初始化的一部分。
答案 3 :(得分:0)
我认为你不必打电话给超级。我尝试模拟以下情况:
class Animal {
}
class Parrot: Animal {
override init() {
// Some code (super not called)
}
}
但是,我建议总是在真实应用中调用super.init,就像你在Objective-C中所做的那样。