我是Swift的新手并且在初始化程序方面遇到了一些问题。我用以下代码创建了一个Swift文件:
if(1){
function foo(){
echo 'foo!';
}
foo(); // No errors, since function is defined!
}
在上面的代码中,if($IsLoggedIn){
// include files/functions and bootstrap here...
}
的{{1}}不包含对import Foundation
class SuperClass
{
var a : Int
init()
{
a = 10
print("In Superclass")
}
}
class SubClass : SuperClass
{
override init()
{
print("In Subclass")
}
}
的{{1}}的调用,即init()
中没有SubClass
所以我的问题是:
如果我不拨打init()
SuperClass
如果我正在创建super.init()
的对象,即SubClass init()
,则输出为:
在子类
中超级课程
为什么要调用init()
的{{1}}?子类init()默认调用超类init()吗?
答案 0 :(得分:1)
据我了解你的问题,你不仅想知道为什么,何时以及如何自动调用初始化程序,而且还抱怨缺少这种行为的文档。
首先,我同意你的观点是缺乏文档 - 就像你一样,我无法找到有关此行为的任何内容,因此应将其添加到Apple的文档中。
为什么调用super.init()
:
根据文档,超类的指定初始值设定项必须由其子类的指定初始值设定项调用,以便完全初始化所有属性。
规则1
指定的初始化程序必须从其中调用指定的初始化程序 直接超类。
上面的代码示例证明它显然是隐式完成的:print("In Superclass")
打印到控制台,因此在创建实例时会以某种方式调用super.init()
。
调用super.init()
的时间和方式:
为了允许编译器隐式调用超类的指定初始值设定项,需要满足一些条件:
超类必须只有一个指定的初始化程序 然后被叫。否则编译器必须选择一个委托 至。这个单一的指定初始化程序也可以是默认值 初始化器或继承的初始化器。
class SuperClass {
var a: Int
init() {
a = 10
}
// introduction of a second designated initializer in superclass:
init(withValue value: Int) {
a = value
}
}
class SubClass: SuperClass {
// won't compile:
// "error: super.init isn't called on all paths before returning from initializer"
override init() {}
}
超类的单个指定初始值设定项不能有任何 参数。毕竟编译器不会知道任何合适的 要传递的参数。
class SuperClass {
var a: Int
// declaration of an initializer with parameter:
init(withValue value: Int) {
a = value
}
}
class SubClass: SuperClass {
// won't compile:
// "error: super.init isn't called on all paths before returning from initializer"
override init() {}
}
子类的指定初始值设定项不得进一步读取或
修改(继承)超类或调用的实例属性
超类的实例方法。那是因为斯威夫特的
两阶段初始化过程及其相应的安全性
检查和隐含委托达到指定的事实
超类的初始化程序发生在结束时
init
- 子类中的语句。
安全检查2
指定的初始值设定项必须最多委托给a 在为继承的值赋值之前的超类初始化程序 属性。如果没有,则新值指定初始化程序 分配将被超类覆盖,作为其自身的一部分 初始化“。
安全检查4
初始化程序无法调用任何实例方法,读取 任何实例属性的值,或将self称为值 直到初始化的第一阶段完成之后。
class SuperClass {
var a: Int
init() {
a = 10
}
}
class SubClass: SuperClass {
// won't compile:
// "error: use of 'self' in property access 'a' before super.init initializes self"
override init() {
a = 10 // modifying inherited self.a before phase 1 of initialization completes isn't valid!
// implicit delegation to super.init()
}
}
安全检查1
指定的初始化程序必须确保所有的 它的类引入的属性在它之前被初始化 委托一个超类初始化器。
class SuperClass {
var a: Int
init() {
a = 10
}
}
class SubClass: SuperClass {
// introduction of instance property "b"
var b: Int
// compiles finely:
override init() {
b = 10 // initializing self.b is required before delegation!
// implicit delegation to super.init()
}
}
我希望有所帮助。
答案 1 :(得分:1)
为什么要调用SuperClass的
init()
?子类init()
默认调用超类init()
吗?
基本上,是的。
如果所有规则都说你应该说super.init()
并且你没有说出来,那就是为你而来。
我不喜欢这种行为;它的记录很少,此外,暗中为你做的事似乎违背了斯威夫特的精神。但是我很久以前就提出了一个针对它的错误,并被告知这是预期的行为。
答案 2 :(得分:0)
您没有访问子类中的超类变量,因此调用了super.init(),后跟子类的init。但是,如果您尝试在子类中使用超类变量而不调用其初始化器,则会导致编译时错误。
答案 3 :(得分:0)
我自己没有尝试过,但Swift Language Guide说:
类类型的初始化程序委派
为简化指定和便利初始值设定项之间的关系,Swift在初始值设定项之间应用以下三个规则进行委托调用:
规则1
指定的初始值设定项必须从其直接超类中调用指定的初始值设定项。
规则2
便捷初始化程序必须从同一个类调用另一个初始值设定项。
规则3
便捷初始化程序必须最终调用指定的初始化程序。
记住这一点的一个简单方法是:
指定的初始值设定项必须始终委派。
便利初始化程序必须始终委派。
因此,调用super.init()
是一个“规则”,如果没有明确实现,它可能只是在内部完成。
答案 4 :(得分:0)
每个类至少有一个指定的初始化程序,它负责初始化实例变量。
以下是doc:
的摘录类往往只有很少的指定初始值设定项,并且一个类只有一个很常见。指定的初始化器是初始发生的“漏斗”点,初始化过程通过该点继续超级链。
每个班级必须至少有一个指定的初始化程序。在某些情况下,通过从超类继承一个或多个指定的初始值设定项来满足此要求,如下面的Automatic Initializer Inheritance中所述。
有关详细信息,请参阅完整文档:https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html
经验法则