- 不需要访问
self
- 不需要访问
self
上的任何属性
init()
方法中,我是否仍然需要调用 super.init()
?*注意:这是一个不同于此处在SO上问答的问题,因为它指定了上述两个细节。
self
self
上的任何属性init()
方法中,我是否仍然需要调用 super.init()
?不,你不必这样做。
假设你有以下的类。
class a {
let name: String
init() {
name = "james"
}
}
class b: a {
let title: String
override init() {
title = "supervisor"
}
}
如果你使用以下语句实例化一个变量:
let myVar = b()
那么:override init()
将被调用。
- 然后在a中调用init()
。
即使你没有显式调用super.init()
。根据文档:
指定的初始化器必须调用其直接超类的指定初始化器。
另外,关于自动初始化器继承:
假设你为子类中引入的任何新属性提供默认值,则以下两个规则适用:
规则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。
是的,指定的初始化程序需要向上委托,因此必须调用 super.init()。 如果您不编写这行代码,则编译器将为您完成。
因此,即使仅在幕后,子类也必须显式地编写super.init(...)
。
但请记住,在第一阶段中,您需要在子类中设置属性,然后必须调用super.init()。 在第二阶段中,可以更改所有继承的属性。 我认为super.init()
是第1阶段和第2阶段之间的完美分隔符。
从文档中获得:
安全检查2
在将值分配给继承的属性之前,指定的初始化程序必须向上委托到超类初始化程序。如果没有这样做,指定的初始化程序分配的新值将被超类覆盖,并成为其自身初始化的一部分。
super.init()
我认为编译器在设置所有属性之后会自动设置它,这意味着您继承的属性都不会使用新值进行设置。为了确保一切正常,我会在设置添加的属性和设置继承的属性之间自己编写super.init()
。(我没有进行广泛尝试,所以也许编译器在这方面是完美的) - Binarian我认为你不必调用super。我尝试模拟以下情况:
class Animal {
}
class Parrot: Animal {
override init() {
// Some code (super not called)
}
}
不过,我建议在实际应用中始终调用 super.init,就像您在 Objective-C 中所做的那样。
super.init()
,它将在子类的 init()
结束时自动调用。您可以通过在基类中添加 init() { fatalError() }
来验证这一点。 - Andres Canella
[super init]
的标准做法了。https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html - bearMountain