Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS Object-Oriented Swift Inheritance Convenience Initializers

Maximiliane Quel
PLUS
Maximiliane Quel
Courses Plus Student 55,489 Points

Using more than one parameter in the convenience initializer

When I try and set only the designer to default, I get an error and am prompted to use the override keyword. Is that correct? Do convenience initialisers only take one parameter? Or do I have to use override with a certain number of parameters? Is it the ratio? Or is that when I am supposed to use a convenience initialiser in another and how would that look? I am a bit confused.

class Clothing: Product {
    var size = Size()
    let designer: String

    init(title: String, price: Double, designer: String){
        self.designer = designer
        super.init(title: title, price: price)
    }

    convenience override init(title: String, price: Double) {
        self.init(title: title, price: price, designer: "Calvin Klein")
    }

    override func discountedPrice(_ percentage: Double = 10) -> Double {
        return super.discountedPrice(percentage)
    }
}

var tshirt = Clothing(title: "Vintage", price: 99)
Jhoan Arango
Jhoan Arango
14,575 Points

Hello Max:

Can you send me the rest of the code ? the product class.. This way I can explain better.

As far as I can see, you are not giving the convenience init the default values.

2 Answers

Jhoan Arango
Jhoan Arango
14,575 Points

Hello Max:

So here is my explanation, I will try to make it as clear as possible.

Here is a great explanation of what a designated, and convenience initializers are used for, this comes from the e-book “The swift programming language” by apple. I recommend reading this as you go through tutorials, it will help you a lot.

Designated Initializers and Convenience Initializers

Designated initializers are the primary initializers for a class. A designated initializer fully initializes all properties introduced by that class and calls an appropriate superclass initializer to continue the initialization process up the superclass chain.

Classes tend to have very few designated initializers, and it is quite common for a class to have only one. Designated initializers are “funnel” points through which initialization takes place, and through which the initialization process continues up the superclass chain.

Every class must have at least one designated initializer. In some cases, this requirement is satisfied by inheriting one or more designated initializers from a superclass, as described in Automatic Initializer Inheritance below.

Convenience initializers are secondary, supporting initializers for a class. You can define a convenience initializer to call a designated initializer from the same class as the convenience initializer with some of the designated initializer’s parameters set to default values. You can also define a convenience initializer to create an instance of that class for a specific use case or input value type.

You do not have to provide convenience initializers if your class does not require them. Create convenience initializers whenever a shortcut to a common initialization pattern will save time or make initialization of the class clearer in intent.”

Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/us/k5SW7.l

class Product {
    let title: String
    var price: Double = 0.0

    init(title: String, price: Double) {
        self.title = title
        self.price = price
    }

    func discountedPrice(percentage: Double) -> Double {
        return price - (price * percentage / 100)
    }
}
enum Size {
    case Small, Medium, Large

    init() { self = .Small }
}

class Clothing: Product {
    var size = Size()
    var designer: String

   // Designated initializer 
    init(title: String, price: Double, designer: String){
        self.designer = designer
        super.init(title: title, price: price)
    }

   // convenient because we only use ONE title, and the rest is added automatically with default values.
    convenience init(title: String) { 
        self.init(title: title, price: 9.99, designer: "Calvin Klein") // Default values

    }

    override func discountedPrice(percentage: Double) -> Double {
        return super.discountedPrice(percentage)
    }

}

The reason why we use a convenience initializer, is so that when we create an instance of that class, we don’t have to repeat something that can be already set by default. For example

var shirt = Clothing(title: "White Shirt") // using a convenient initializer  
var jean = Clothing(title: "Blue Jean", price: 29.99, designer: "Levis") // using designated initializer


shirt.designer // will print Calvin Klein
jean.designer // will print Levis

Notice how with the convenient we only put the title and not worried about the rest since it’s already set with default values, when using the designated we have to give them values.

Now the reason why it’s telling you to use override, it’s because you are creating 2 identical initializers, in that case you can just change the name of one of the parameters, and create a different initializer. Like this

    convenience init(title: String, price2: Double) { // Notice second parameter
        self.init(title: title, price: price2, designer: "Calvin Klein") 

    }

// This will not give you that “override” error. But when you create an instance it will look 
// like this.

var blackShirt = Clothing(title: "BlackShirt", price2: 59.99)

Hope you get it.

Jhoan Arango
Jhoan Arango
14,575 Points

You are very welcome, hope that was clear and that you now understand. If you have anymore questions, please feel free to tag me @ jhoanarango

Maximiliane Quel
PLUS
Maximiliane Quel
Courses Plus Student 55,489 Points

Hi,

here is the entire thing:

class Product {
    let title: String
    var price: Double = 0.0

    init(title: String, price: Double) {
        self.title = title
        self.price = price
    }

    func discountedPrice(percentage: Double) -> Double {
        return price - (price * percentage / 100)
    }
}

enum Size {
    case Small, Medium, Large

    init() { self = .Small }
}

class Clothing: Product {
    var size = Size()
    let designer: String

    init(title: String, price: Double, designer: String){
        self.designer = designer
        super.init(title: title, price: price)
    }

    convenience override init(title: String, price: Double) {
        self.init(title: title, price: price, designer: "Calvin Klein")
    }

    override func discountedPrice(_ percentage: Double = 10) -> Double {
        return super.discountedPrice(percentage)
    }
}

var tshirt = Clothing(title: "Vintage", price: 99)

It will take just title without the override when price is set to a default value in the convenience method:

    convenience init(title: String) {
        self.init(title: title, price: 99, designer: "Calvin Klein")
    }

but as soon as I add the price to the parameter as above it will give me an error and ask for the override keyword ...