Blog

[Swift] Class Initialization Safety Checks

Published 2 min read

class Human { var name: String var age: Int init(name: String, age: Int) { self.name = name self.age = age } }
class Student: Human { var school: String init(name: String, age: Int, school: String) { self.school = school super.init(name: name, age: age) } }
class UnivStudent: Student { var major: String init(name: String, age: Int, school: String, major: String) { self.major = major super.init(name: name, age: age, school: school) } convenience init(age: Int) { self.init(name: "unknown", age: age, school: "Stanford", major: "computer") } }

Inheritance chain

Inheritance chain

Let's look at the safety checks the compiler needs
before a class's initialization process.

Safety checks

This is a process the compiler performs.
It runs 4 checks.
① All properties of the current class must be initialized before the parent class's init runs.

init(name: String, age: Int, school: String, major: String) { self.major = major super.init(name: name, age: age, school: school) }

In the UnivStudent class, the current class's property is major.
Through self.major = major, it checks that all of UnivStudent's properties are initialized.
The parent class can't initialize properties that only the child class has, so this check is performed.

② Properties inherited from the parent must be assigned after the parent's initialization finishes.

init(name: String, age: Int, school: String, major: String) { self.major = major self.age = 14 // ERROR! super.init(name: name, age: age, school: school) }

self.age is a property inherited from the Human class.
But it tried to initialize this value before calling the parent's initializer, so an error occurs.

③ Same as ②, in a convenience initializer you also have to initialize properties after calling the designated initializer.

convenience init(age: Int) { self.age = 14 // ERROR self.init(name: "unknown", age: age, school: "Stanford", major: "computer") }

④ Before phase 1 of initialization is done, you can't call instance properties/methods' properties,
and you can't reference the self property.

class UnivStudent: Student { var major: String var me: UnivStudent = self // ERROR! var me: UnivStudent = { self }() // ERROR! var me: UnivStudent { self } // Okay init(name: String, age: Int, school: String, major: String) { self.major = major me = self // ERROR! super.init(name: name, age: age, school: school) } convenience init(age: Int) { self.init(name: "unknown", age: age, school: "Stanford", major: "computer") } }

A stored property can't reference self while phase 1 initialization isn't complete.
But a computed property doesn't reference self, it just returns a value, so it's allowed.

Comments

Leaving a comment stores your nickname (or GitHub profile info). Privacy policy

GitHub