Consider the two classes:
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' } }
I don't see why this isn't allowed. Ultimately, each class's designated initializer is called with any values they need, so why do I need to repeat myself in B
's init
by specifying a default value for x
again, when the convenience init
in A
will do just fine?
Conversely, if you write a subclass initializer that matches a superclass convenience initializer, that superclass convenience initializer can never be called directly by your subclass, as per the rules described above in Initializer Delegation for Class Types.
Convenience initializers are secondary, supporting initializers for a class. You can define a convenience initializer to call a designated initializer from the same class as the convenience initializer with some of the designated initializer's parameters set to default values.
“If the initializer you are overriding is a convenience initializer, your override must call another designated initializer from its own subclass.”
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.
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html
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:).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With