为什么Swift初始化器不能在它们的超类中调用便捷初始化器?

考虑这两个类:

class A { var x: Int init(x: Int) { self.x = x } convenience init() { self.init(x: 0) } } class B: A { init() { super.init() // Error: Must call a designated initializer of the superclass 'A' } } 

我不明白为什么这是不允许的。 最终,每个类的指定初始化器都被调用了它们需要的任何值,那么为什么我需要在Binit再次指定一个默认值来重复自己呢?

这是Swift编程指南中规定的“初始化链接”规则的规则1,其内容如下:

规则1: 指定的初始化器必须从它们的直接超类中调用一个指定的初始化器。

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html

强调我的。 指定的初始化器不能调用便捷初始化器。

有一个图表,遵循规则来演示什么初始化“方向”是允许的:

初始化链接

考虑

 class A { var a: Int var b: Int init (a: Int, b: Int) { print("Entering A.init(a,b)") self.a = a; self.b = b } convenience init(a: Int) { print("Entering A.init(a)") self.init(a: a, b: 0) } convenience init() { print("Entering A.init()") self.init(a:0) } } class B : A { var c: Int override init(a: Int, b: Int) { print("Entering B.init(a,b)") self.c = 0; super.init(a: a, b: b) } } var b = B() 

由于类A的所有指定初始化符都被覆盖,因此类B将inheritanceA的所有便捷初始化符

 Entering A.init() Entering A.init(a:) Entering B.init(a:,b:) Entering A.init(a:,b:) 

现在,如果允许指定初始化函数B.init(a:b :)来调用基类便利初始值设定项A.init(a :),则会导致对B.init(a:,b: )。

这是因为你可以以无限的recursion结束。 考虑:

 class SuperClass { init() { } convenience init(value: Int) { // calls init() of the current class // so init() for SubClass if the instance // is a SubClass self.init() } } class SubClass : SuperClass { override init() { super.init(value: 10) } } 

并看看:

 let a = SubClass() 

这将调用SubClass.init()将调用SuperClass.init(value:) ,这将调用SubClass.init()

指定的/便利的初始化规则被devise成类初始化将始终是正确的。

我find了一个工作。 这不是超级漂亮,但它解决了不知道超类的值或想要设置默认值的问题。

你所要做的就是创build一个超类的实例,使用便利的init ,就在子类的init中。 然后你使用刚刚创build的实例调用super的指定init

 class A { var x: Int init(x: Int) { self.x = x } convenience init() { self.init(x: 0) } } class B: A { init() { // calls A's convenience init, gets instance of A with default x value let intermediate = A() super.init(x: intermediate.x) } } 

在18:30看WWDCvideo“403中级Swift”,以深入解释初始值及其inheritance。 据我了解,请考虑以下几点:

 class Dragon { var legs: Int var isFlying: Bool init(legs: Int, isFlying: Bool) { self.legs = legs self.isFlying = isFlying } convenience initWyvern() { self.init(legs: 2, isFlying: true) } } 

但现在考虑一个龙类 – 一个龙类,一个没有双腿,没有翅膀的龙。 所以一个双足飞行器的初始化(2腿,2翅膀)是错的! 如果方便的Wyvern-Initializer不能被调用,但只有完整的指定的初始化程序:

 class Wyrm: Dragon { init() { super.init(legs: 0, isFlying: false) } } 

你为什么不只有两个初始化器 – 一个是默认值?

 class A { var x: Int init(x: Int) { self.x = x } init() { self.x = 0 } } class B: A { override init() { super.init() // Do something else } } let s = B() sx // 0 

考虑准确的初始化代码从你方便的init()到一个新的辅助函数foo(),调用foo(…)在你的子类中进行初始化。