I am new to Swift and getting some problem regarding initializers. I have created a Swift file with the following code :
import Foundation
class SuperClass
{
var a : Int
init()
{
a = 10
print("In Superclass")
}
}
class SubClass : SuperClass
{
override init()
{
print("In Subclass")
}
}
In the above code, init()
of SubClass
does not contain call to init()
of SuperClass
i.e. there is no super.init()
in SubClass init()
.
So my question is:
1. Why is it not giving any error if I don't call designated init()
of SuperClass
2. If I am creating an object of SubClass
i.e. let s = SubClass()
, the output is :
In Subclass
In Superclass
Why the init()
of SuperClass
is getting called? Does a subclass init() calls the superclass init() by default?
As far as I understood your question, you're not only wondering why, when and how the initializer gets called automatically, but also complaining about the missing documentation of this behavior.
First of all I agree with you on the lack of documentation - just like you I'm not able to find anything about this behavior and therefore it should be added to the documentation by Apple.
Why super.init()
is called:
As per documentation a designated initializer of the superclass has to be called by a designated initializer of its subclass in order to fully initialize all properties.
Rule 1
A designated initializer must call a designated initializer from its immediate superclass.
Your code example above proves it's obviously done implicitly: print("In Superclass")
prints to the console, so super.init()
is somehow invoked while creating an instance.
When and how super.init()
is called:
There are some conditions to be met in order to allow the compiler to call the designated initializer of the superclass implicitly:
The superclass must have only one designated initializer which is then called. Otherwise the compiler had to choose one to delegate to. This single designated initializer could be also the default initializer or an inherited initializer.
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() {}
}
The single designated initializer of the superclass mustn't have any parameters. After all the compiler wouldn't know any appropriate parameter to be passed.
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() {}
}
The designated initializer of the subclass mustn't further read or
modify (inherited) instance properties of the superclass or call
instance methods of the superclass. That's because of Swift's
two-phase initialization process with its corresponding safety
checks and the fact that the implicit delegation up to the designated
initializer of the superclass happens at the end of the
init
-Statement in the subclass.
Safety check 2
A designated initializer must delegate up to a superclass initializer before assigning a value to an inherited property. If it doesn’t, the new value the designated initializer assigns will be overwritten by the superclass as part of its own initialization.“
Safety check 4
An initializer cannot call any instance methods, read the values of any instance properties, or refer to self as a value until after the first phase of initialization is complete.
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()
}
}
Safety check 1
A designated initializer must ensure that all of the properties introduced by its class are initialized before it delegates up to a superclass initializer.
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()
}
}
I hope that helps.
Why the
init()
of SuperClass is getting called? Does a subclassinit()
calls the superclassinit()
by default?
Basically, yes.
If all the rules say that you should say super.init()
and you don't say it, it is called for you.
I don't like this behavior; it is poorly documented, and besides, secretly doing stuff for you seems against the spirit of Swift. But I filed a bug against it long ago and was told it was intended behavior.
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