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 2.0 Complex Data Structures Custom Initializers

Objective-Oriented Swift 2.0 - Custom Initializers

In the editor, I’ve declared a struct named RGBColor that models a color object in the RGB space.

Your task is to write a custom initializer method for the object. Using the initializer assign values to the first four properties. Using the values assigned to those properties create a value for the description property that is a string representation of the color object.

For example, given the values 86.0 for red, 191.0 for green, 131.0 for blue and 1.0 for alpha, each of the stored properties should hold these values and the description property should look like this:

"red: 86.0, green: 191.0, blue: 131.0, alpha: 1.0"

Note: Init methods typically list parameters in the same order of property declaration. For this task, stick to the order red,green,blue,alpha.

"Bummer! Don't use the memberwise initializer Swift creates. Add your own custom initializer as specified in the directions"

structs.swift
struct RGBColor {
    let red: Double
    let green: Double
    let blue: Double
    let alpha: Double

    let description: String

     // Add your code below
      init(){
      red = 86.0 
      green = 191.0
      blue = 131.0
      alpha = 1.0
      description = "red: \(red), green: \(green), blue: \(blue), alpha: \(alpha)"
    }
}

19 Answers

Hi Gonzalo,

The init method is used to construct the instance of the struct using values passed in as parameters. The values given in the challenge are just examples, not to be hard-coded.

So, the init method takes four parameters, RGB & A. You've done the description one correctly; that's the hard bit!!

So, modify your method to take the four color parameters, and the assign the values passed in to the stored properties inside the method.

init(red: Double, green: Double, blue: Double, alpha: Double){
  self.red = red
  self.green = green
  self.blue = blue
  self.alpha = alpha

  self.description = "red: \(red), green: \(green), blue: \(blue), alpha: \(alpha)"
}

Make sense?

Steve.

thanks!!

No problem!

Michael Harris
Michael Harris
1,528 Points

Good explanation Steve!

It helped me understand why we say: Self.red = red etc.

Am I correct to say that it basically means that whatever double value is passed into init(red: Double) etc. the constant in struct RGBColor { let red: Double } should be equal to that?

That is the reason why you are saying the "hard coding" is wrong. Even if you pass a value into var myRGB = RGBColor(red: value) it won't change because you hard coded it when creating the init.

Hi Michael,

Yes, the value passed into the init method (red: Double) is assigned to the stored property inside the struct: let red: Double. That's what the init method does; it allows the user to send in stored properties at the time the instance is created.

The hard coding that I was referring to was when the init method had self.red = 86.0. So whatever number was passed into the method was ignored and the value 86 assigned to red irrespective. Further, you can't amend the value assigned to red after the instance is created as it is defined with let not var.

Whatever you pass in with the hard-coded init method (the one with the specific numbers in it), the parameters won't affect the object that is created. Every object will be created with the same numbers which can't be changed after instantiation.

Take this from my above post:

    init(red: Double, green: Double, blue: Double, alpha: Double){
        self.red = 86.0
        self.green = 191.0
        self.blue = 131.0
        self.alpha = 1.0
        self.description = "red: \(red), green: \(green), blue: \(blue), alpha: \(alpha)"
    }

var myRGB = RGBColor(red: 30.0, green: 100.0, blue: 41.0, alpha: 15.0)

The values in the last line, the parameters passed to the init method are used only in description - they are correctly interpolated into the string with \(red) \(green), etc. They aren't used in the stored properties as those are assigned the values coded into the init method. Every instance of this struct will have the values set inside the initializer, not passed to it by the user.

Happy with that explanation?

Steve.

This is what I submitted and seems to be working without error:

struct RGBColor {
    let red: Double
    let green: Double
    let blue: Double
    let alpha: Double

    let description: String

    // Add your code below
    init(red: Double, green: Double, blue: Double, alpha: Double){
     self.red = 86.0
        self.green = 191.0
        self.blue = 131.0
        self.alpha = 1.0
        self.description = "red: \(red), green: \(green), blue: \(blue), alpha: \(alpha)"

    }
}
let myRGB = RGBColor(red: 86.0, green: 191.0, blue: 131.0, alpha: 1.0)

myRGB.description  //red: 86.0, green: 191.0, blue: 131.0, alpha: 1.0

That does pass, which is a shame because the code isn't correct as the initializer shouldn't hard-code the values. Your init method takes four parameters and then totally ignores them and assigns fixed-values into the stored properties. Whatever you pass into the constructor/init method, an object with the same 4 values is created. The thread above explains why that is the case; shout if you don't see what that's about.

I'll report this as a bug and get it fixed! One for Pasan Premaratne , I think!

Steve.

I've let the guys know and I will keep you posted as to progress. :+1:

It's interesting; the description will be correct as that uses the passed-in values, but the object won't be as that doesn't. The tests aren't picking up on that.

I think it's not Fixed value, it's only initial values and can be changed by new values. you can look at them like a default values therefore it's not a bug. this one also works:

    struct RGBColor {
    let red: Double
    let green: Double
    let blue: Double
    let alpha: Double

    let description: String

    // Add your code below
    init(red: Double, green: Double, blue: Double, alpha: Double){
     self.red = red
        self.green = green
        self.blue = blue
        self.alpha = alpha
        self.description = "red: \(red), green: \(green), blue: \(blue), alpha: \(alpha)"

    }
}
let myRGB = RGBColor(red: 30.0, green: 100.0, blue: 41.0, alpha: 15.0)
myRGB.description  //"red: 30.0, green: 100.0, blue: 41.0, alpha: 15.0"

Yes, it is a bug. The hard-coded example shouldn't work.

Raphael Reiter
Raphael Reiter
6,820 Points

Steve Hunter : Hey !

Could you help me understand a bit better? here is my code and it doesnt seem to be correct. thanks !

struct RGBColor {
    let red: Double
    let green: Double
    let blue: Double
    let alpha: Double

    let description: String

    // Add your code below
    init(red: Double, green: Double, blue: Double, alpha: Double) {
        self.red = 86.0
        self.green = 191.0
        self.blue = 131.0
        self.alpha = 1.0
    }

}

Hi Raphael,

The values for the RGBA elements given in the challenge are examples only. You can use them to test the init method, but you want the RGBColor struct to work for any color.

So, the values you use inside he init are those that get passed in when the user creates an instance of the struct. Using the numbers in the question, to create a struct, you would type something like:

let exampleColor = RGBColor(red: 86.0, green: 191.0, blue: 131.0, alpha: 1.0)

Those numbers could be any number between zero and 255. That covers all the colors! So, to get your code to work, you just need to change the numbers to the argument names. Change 86.0 to red (that's the value passed in above, right?), change 191.0 to green and so on.

Your final init method looks like:

init(red: Double, green: Double, blue: Double, alpha: Double){
  self.red = red
  self.green = green
  self.blue = blue
  self.alpha = alpha
  /// define description here
}

The description piece is a little trickier and needs you to use some string interpolation. Have a go and shout back if you need a hand.

Steve.

Raphael Reiter
Raphael Reiter
6,820 Points

Thanks Steve Hunter.

I still don't get the description. I saw the answers but i don't really get how it will print or return what we will need here, which if i understand correcly, is a description of those 4 colours?

The description is just another stored property of the struct. It is there for a user to access if they wish. The struct itself doesn't concern itself with printing it out - it just stores the value.

So, using string interpolation, the (var) thing, we can build the sentence that the challenge is asking for:

self.description = "red: \(red), green: \(green), blue: \(blue), alpha: \(alpha)"

With the code we wrote above, that would mean that description will now hold a string that says, red: 86.0, green: 191.0, blue: 131.0, alpha: 1.0. Should anyone using the struct, like the one we created above (exampleColor), want to print out that string, they can use something like:

print(exampleColor.description)

That accesses the stored property of the struct using dot notation. The description property is not passed into the initmethod as a parameter, it is created from the other stored properties that are passed in as parameters. So, all instances of RGBColor structs will have four numbers held as stored properties, the RGBA bits, and a nice string description that can all be accessed using the notation, like above.

I hope that helps.

Steve.

Why won't the following work for this?

struct RGBColor {
    let red: Double
    let green: Double
    let blue: Double
    let alpha: Double

    let description: String

    init(r: Double, g: Double, b: Double, a: Double) {
        self.red = r
        self.green = g
        self.blue = b
        self.alpha = a
        self.description = "red: \(r), green: \(g), blue: \(b), alpha: \(a)"
    }
}

There's nothing wrong with that code, as far as I can tell. However, the challenge compiler thinks you are using a default initializer, rather than having created your own. The error it throws implies that - I can't tell you more than that, I am afraid. I don't know why it fails - the code looks good to me.

Thanks, Steve. Just checking since it seemed to work fine in Xcode

Yeah, I think this might be one of the very rare instances where "it works in Xcode" is relevant. Be wary of posting that line - you'll see it a lot in the forum posts. 'Working in Xcode' and doing what the challenge wants are often two totally different things! This one, I think you're right, though. I just changed, r for red etc. and the code passed the tests. I'll flag it with Support as it is a strange one that warrants explanation, I think. I'll let you know when I get that!

Cheers,

Steve.

Thanks :). I'd be interested to know

I've submitted the request and will let you know what I get back. Something to do with your code looking like an auto-generated initializer, I think as the error was: Don't use the memberwise initializer Swift creates. Add your own custom initializer as specified in the directions

Pasan Premaratne
Pasan Premaratne
Treehouse Teacher

So the issue here is that for the challenge I have to look for the declaration of specific parameters in the initializer. The error message is vague...that can be fixed, but the reason for requiring specific parameters is just because of what Swift allows me to do under the hood for these challenges

Thanks Pasan Premaratne ,

But why is r not a specific parameter, while red is? The above code, which fails, is identical to the code that passes except for the shorter names, r rather than red, g rather than green etc.

Steve.

Pasan Premaratne
Pasan Premaratne
Treehouse Teacher

Steve Hunter

I chose "red", "green", etc..because if Swift created a memberwise initializer automatically for you, it would use the property names. That's the convention.

The challenge is hardcoded to look for "red" specifically because there's an infinite number of parameter names you can chose from and I can't account for every single one. I went with that most common, if that makes sense.

For what its worth (not that we test this), I'd go as far as to say "r" is a wrong choice of name. Swift and iOS have pretty strict conventions around naming and the guideline is to be verbose and descriptive with your names.

But yeah, "r" works in Xcode because Xcode is not looking for anything specific, while I am.

Thanks Pasan,

I hadn't realised you'd tested the names of the parameters - that makes sense now. I thought you tested that the initializer created an object properly, in accordance with the instructions.

Thanks,

Steve.

Pasan Premaratne
Pasan Premaratne
Treehouse Teacher

I'd love not to test the parameter names to be honest, but there's no way around it. Initializers are pretty hardcoded to their names under the hood.

well that's not good. Could you please show me the correct way so I can study it instead. Thank you in advance

Hiya,

The/one correct way is marked as 'Best Answer' in this thread. That code performs the same as your code in your later post. My reference to a bug related to your first post which contained incorrect code which passed the challenge.

I think it is more important to understand why the code in your first post isn't correct, rather than getting immersed in being right. Do you see that?

Steve.

well thanks for the advice. Your only argument is, "Hard-coded" shouldn't go through and I think Initialisation with values is not "hard-coded". if it was, we wouldn't be able to change the values of (let) them by an instance later on.

this is "hard-coded" example:

    struct RGBColor {
    let red: Double
    let green: Double
    let blue: Double
    let alpha = 1.0 // Alpha can't be changed anymore
}

Hi Rzgar,

Each object your code created is hard coded to the extent that their properties are determined by the code, not the user's choice of values passed to the parameter. We're talking about your original post here, the one I flagged as an issue with the compiler.

Take the init method:

    init(red: Double, green: Double, blue: Double, alpha: Double){
        self.red = 86.0
        self.green = 191.0
        self.blue = 131.0
        self.alpha = 1.0
        self.description = "red: \(red), green: \(green), blue: \(blue), alpha: \(alpha)"
    }

Let's say we create a variable instance of this and pass in:

var myRGB = RGBColor(red: 30.0, green: 100.0, blue: 41.0, alpha: 15.0)

Then, the objects created by this will always have the same colour properties; only their description will be different and contradictory to the acual contents of the object. Let's focus on red. We've passed in 30. What will myRGB.red have in it? 86.0. But the description will say "red: 30.0". Can we change this value? No - it is a constant even if the myRGB variable isn't. So myRGB.red = 86.0 fails because red is initialized and cannot be changed after that.

So, whilst your stored properties might not be hard-coded inside the struct; they are inside the constructor. Every object will hold the same values of red, green, blue and alpha that will not be changable in code.

That is how I meant the values are hard-coded. Make sense?

Steve.

huh, all these times I was checking my argument based on non-flagged example in my xcode and I saw the value of myRGB.red was indeed changed. After copy-pasting my first code, the flagged one, I understood what you meant form the beginning. Now I feel I learned something. Thank you very much for clearing it out for me. Appreciate it.

Hey, no problem! :wink: :+1:

Michael Harris
Michael Harris
1,528 Points

Yes, perfect. Thanks a lot!

Perry Clark
Perry Clark
8,261 Points

I found this test description quite hard

Hi Perry,

Which bit is causing the confusion? This thread covered a lot of ground!!

Steve.

Perry Clark
Perry Clark
8,261 Points

The thread helped me solve it ok. I've not struggled with any tests except this one

As long as you're OK to continue, that's great. :+1: :smile:

Could anyone describe more clearly why we used .description to call this method??

struct RGBColor {
  let red: Double
  let green: Double
  let blue: Double
  let alpha: Double

  let description: String


  init() {
        self.red = 86.0
        self.green = 191.0
        self.blue = 131.0
        self.alpha = 1.0

        self.description = "red: \(red), green: \(green), blue: \(blue), alpha: \(alpha)"
    }
}

This is my code but I have no idea of why it isn't working. When I look at the preview nothing shows and I'm not being told what specifically is wrong with the code, it just says it can't be compiled. Does anyone know what's wrong with this?

Of course I can try to help - can you link me to the challenge? This is a very old thread on an out-of-date Swift version! I'll look at the challenge and get your code fixed if you can link me.

Steve.

OK - there's two things here. First, the numbers given in the challenge are just examples. The user should be able to create a struct with any values held by each RGBA.

So, rather than assign the values into self.red inside init, have the init method receive these values from the user, i.e. make them parameters of the init method. Inside init assign the received parameter into the self.red stored property.

Include four parameters for the init method and assign them into the stored properties inside init.

Steve.

Ohh. Thanks, I finally got it!