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 Build a Playlist Browser with Objective-C Managing Playlist Data Class Initialization

Why do we use _ instead of setter ?

The instructor mentioned that we almost always use setter method to set property. However, he said that we need to use the _ in the init method. Why do we need to use the _ in this case ? Also, how is it different from setter ?

ie. how is:

_playlistTitle = @"Abbey Road";

differ from:

self.playlistTitle = @"Abbey Road";

thanks!

1 Answer

Ravee Sundar
PLUS
Ravee Sundar
Courses Plus Student 1,975 Points

The main reason we use instance variables instead of the actual setter is because of subclassing. Here is an example of things going poorly by using setters instead of directly accessing the instance variable. If we think of a class called Animal with a property called noise we would initialize this class like this:

  • (instancetype) init { self = [super init]; if (self) { self.noise = @"rawr"; } return self; } This will probably work without any odd side-effects or anything going wrong. That is until we subclass our Animal class with Dog. Let's say in Dog we modify the setter to do a bit more work then just setting the variable. Let's make the Dog class's noise setter to grab it's name and include that in the noise it makes. Something like this:

  • (void) setNoise: (NSString *)noise { NSString *dogNoise = [NSString stringWithFormat:@"%@ %@ %@", noise, self.name, noise]; // for fido outputs "noise fido noise" [super setNoise:dogNoise];
    } Now let's write the init method for our Dog class.

  • (instancetype) init { self = [super init]; if (self) { self.name = @"Fido"; } return self; } Now in our code let's do Dog *fido = [[Dog alloc] init];. If we take a look at what the noise property is of fido is we see it's @"rawr (null) rawr". That's unexpected! This can be a bit hard to understand what happened but let's follow the chain of methods that we created. First things first we call the init instance method on the Dog class. We are then encountered with this line of code: self = [super init]. This kicks us up to the init instance method in the Animal class which calls the noise setter on self. The question is...what is self in this case? Self is an instance of the Dog class! So that brings us to the setter created in the Dog class. The setter in the Dog class grabs the name property...which hasn't been set yet. That's how you get the nil in for the name.

Semi-Completed Self So the first issue here is you are never sure when a class you write will get subclassed. We need to be aware of those possible issues like the one above. To do this we just never use self until self is completely finished being created. During our init method we are in a state of flux. Our instance has just started being created, but hasn't finished. Because of this, we can't rely on self being completely set up like we can elsewhere in our class. So, in the init method, we must never use a method on self.

Note: (I grabbed a segment from the following blog by Joe): http://joemburgess.com/2014/10/13/why-the-underscores-in-init/

So - Thanks Joe Burgess.