为什么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' } }
我不明白为什么这是不允许的。 最终,每个类的指定初始化器都被调用了它们需要的任何值,那么为什么我需要在B
的init
再次指定一个默认值来重复自己呢?
这是Swift编程指南中规定的“初始化链接”规则的规则1,其内容如下:
规则1: 指定的初始化器必须从它们的直接超类中调用一个指定的初始化器。
强调我的。 指定的初始化器不能调用便捷初始化器。
有一个图表,遵循规则来演示什么初始化“方向”是允许的:
考虑
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(…)在你的子类中进行初始化。