Search code examples
iosswiftoopinheritanceinitialization

How to delegate up to a superclass initializer before assigning a value to an inherited property


Swift documentation says here in regards to the initializer delegation:

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.

Let's say in the following example:

class Shape {
    var color: String
    
    init(color: String) {
        self.color = color
    }
}

class Circle: Shape {
    let pi = 3.14
    var r: Double
    
    init(r: Double, color: String) {
        self.r = r
        super.init(color: color)
    }
    
    func area() -> Double {
        return pi * r * r
    }
}

what does it mean to "delegate up to a superclass initializer before assigning a value to an inherited property"? My assumption is that the "inherited property" means none of the properties newly introduced by the subclass.

Isn't the very act of delegating up to a superclass initializer, super.init(color: color), assigning a value to inherited property? How do I assign to the inherited properties first and then delegate up to a superclass initializer? What would be an example of the new value being overwritten by the superclass initializer?


Solution

  • Your example doesn't actually involve the modifying an inherited property in a subclass initialiser. An inherited property is a property declared by the superclass (such as color in your example).

    That piece of documentation says that if you want to override the behaviour of the super initialiser and modify the value of an inherited property in the subclass init, you first need to call super.init and only then can you modify the value. This is because all values declared by the superclass will be initialised in super.init.

    Actually, the compiler doesn't even allow you to access values declared in the superclass before calling super.init to avoid the errors mentioned by the documentation.

    Check the below example, where the superclass assigns a constant value to id, regardless of what the input value to the init was, while the subclass uses the input value and hence overrides the value assigned in the superclass.

    class Super {
        var id: Int
    
        init(id: Int) {
            self.id = 0
        }
    }
    
    class Sub: Super {
        let prop: String
    
        init(id: Int, prop: String) {
            self.prop = prop
            // The next line would actually result in the error: 'self' used in property access 'id' before 'super.init' call
            //self.id = id 
            super.init(id: id)
            self.id = id // this is where you can override a property declared by the superclass
        }
    }
    
    Sub(id: 2, prop: "") // id is correctly initialised to 2