From the docs
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.
Why do we need a safety check like this?
To answer this lets go though the initialization process in swift.
Two-Phase Initialization
Class initialization in Swift is a two-phase process. In the first
phase, each stored property is assigned an initial value by the class
that introduced it. Once the initial state for every stored property
has been determined, the second phase begins, and each class is given
the opportunity to customize its stored properties further before the
new instance is considered ready for use.
The use of a two-phase initialization process makes initialization
safe, while still giving complete flexibility to each class in a class
hierarchy. Two-phase initialization prevents property values from
being accessed before they are initialized, and prevents property
values from being set to a different value by another initializer
unexpectedly.
So, to make sure the two step initialization process is done as defined above, there are four safety checks, one of them is,
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.
Now, the two phase initialization never talks about order, but this safety check, introduces super.init
to be ordered, after the initialization of all the properties.
Safety check 1 might seem irrelevant as,
Two-phase initialization prevents property values from being accessed before they are initialized can be satisfied, without this safety check 1.
Like in this sample
class Shape {
var name: String
var sides : Int
init(sides:Int, named: String) {
self.sides = sides
self.name = named
}
}
class Triangle: Shape {
var hypotenuse: Int
init(hypotenuse:Int) {
super.init(sides: 3, named: "Triangle")
self.hypotenuse = hypotenuse
}
}
Triangle.init
has initialized, every property before being used. So Safety check 1 seems irrelevant,
But then there could be another scenario, a little bit complex,
class Shape {
var name: String
var sides : Int
init(sides:Int, named: String) {
self.sides = sides
self.name = named
printShapeDescription()
}
func printShapeDescription() {
print("Shape Name :\(self.name)")
print("Sides :\(self.sides)")
}
}
class Triangle: Shape {
var hypotenuse: Int
init(hypotenuse:Int) {
self.hypotenuse = hypotenuse
super.init(sides: 3, named: "Triangle")
}
override func printShapeDescription() {
super.printShapeDescription()
print("Hypotenuse :\(self.hypotenuse)")
}
}
let triangle = Triangle(hypotenuse: 12)
Output :
Shape Name :Triangle
Sides :3
Hypotenuse :12
Here if we had called the super.init
before setting the hypotenuse
, the super.init
call would then have called the printShapeDescription()
and since that has been overridden it would first fallback to Triangle class implementation of printShapeDescription()
. The printShapeDescription()
of Triangle class access the hypotenuse
a non optional property that still has not been initialised. And this is not allowed as Two-phase initialization prevents property values from being accessed before they are initialized
So make sure the Two phase initialization is done as defined, there needs to be a specific order of calling super.init
, and that is, after initializing all the properties introduced by self
class, thus we need a Safety check 1