Why can't Swift initializers call convenience initializers on their superclass?
This is Rule 1 of the "Initializer Chaining" rules as specified in the Swift Programming Guide, which reads:
Rule 1: Designated initializers must call a designated initializer from their immediate superclass.
Emphasis mine. Designated initializers cannot call convenience initializers.
There is a diagram that goes along with the rules to demonstrate what initializer "directions" are allowed:
Consider
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()
Because all designated initializers of class A are overridden, class B will inherit all convenience initializers of A. So executing this will output
Entering A.init()Entering A.init(a:)Entering B.init(a:,b:)Entering A.init(a:,b:)
Now, if the designated initializer B.init(a:b:) would be allowed to call the base class convenience initializer A.init(a:), this would result in a recursive call to B.init(a:,b:).
It's because you can end up with an infinite recursion. Consider:
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) }}
and look at:
let a = SubClass()
which will call SubClass.init()
which will call SuperClass.init(value:)
which will call SubClass.init()
.
The designated/convenience init rules are designed that a class initialisation will always be correct.