Search code examples
iosswiftinitializationsubclasssuperclass

confusion over initialisation in swift


According to "Swift programming language 2.1", if a subclass provides default value for all of its properties, then the subclass automatically inherits all its superclass's designated initialisers and convenience initialisers. So for the code below, class ShoppingListItem should inherit three initialisers, from its superclass, RecipeIngredient, i.e.

//1
convenience init() {
    self.init(name: "[unnamed]")
}

//2
convenience init(name: String){
    self.init(name: name, quantity: 1)
}

//3
init(name: String, quantity: Int){
    self.quantity = quantity
    super.init(name: name)
}

If I want to create an instance of ShoppingListItem, I would write

let ingredientThree = ShoppingListItem(name: "apple", quantity: 10)

this would invoke the init(name: String, quantity: Int){}, but within this initialiser, there is a call to super.init(name: name), this is where I'm getting stuck. What happen when the initialisation process has reached super.init(name: name)? Does it call ShoppingListItem's superclass's init(name: String){} initialiser? Or does it not? What exactly happen here? Could someone please kindly explain it to me? Thanks in advance for any help!

Actual code:

class Food {
    var name: String
    init(name: String){
        self.name = name
    }
    convenience init() {
        self.init(name: "[unnamed]")
    }

}

class RecipeIngredient: Food{
    var quantity: Int
    init(name: String, quantity: Int){
        self.quantity = quantity
        super.init(name: name)
    }

    override convenience init(name: String){
        self.init(name: name, quantity: 1)
    }
}

class ShoppingListItem: RecipeIngredient {
    var purchased = false
    var description: String {
        var output = "\(quantity) X \(name)"
        output += purchased ? " ✔" : " ✘"
        return output
    }
}

Graph from Swift programming language 2.1 enter image description here


Solution

  • I put your code into a playground and added some prints. Here is what happens:

    • RecipeIngredient.init(String, Int)
    • Food.init

    Incidentally, you asked if it will call ShoppingListItem's superclass's init(name: String){} initializer.

    The answer is no. Your used

    let ingredientThree = RecipeIngredient(name: "apple", quantity: 10)
    

    This has nothing to do with ShoppingListItem.

    Generally, if you have class inheritance Class1 <- Class2 <- Class3. And then you instantiate Class2, then Class 3 never comes into play.

    class Food {
        var name: String
        init(name: String){
            print("Food.init")
            self.name = name
        }
        convenience init() {
            self.init(name: "[unnamed]")
        }
    
    }
    
    class RecipeIngredient: Food{
        var quantity: Int
        init(name: String, quantity: Int){
            print("RecipeIngredient.init(String, Int)")
            self.quantity = quantity
            super.init(name: name)
        }
    
        override convenience init(name: String){
            self.init(name: name, quantity: 1)
        }
    }
    
    class ShoppingListItem: RecipeIngredient {
        var purchased = false
        var description: String {
            var output = "\(quantity) X \(name)"
            output += purchased ? " ✔" : " ✘"
            return output
        }
    }
    let ingredientThree = RecipeIngredient(name: "apple", quantity: 10)