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 Complex Data Structures Initializers and Self

Kristopher Wood
seal-mask
.a{fill-rule:evenodd;}techdegree
Kristopher Wood
iOS Development Techdegree Student 5,552 Points

Can you help me understand self better?

I'm getting confused about what self refers to within a struct or class. The use of similar syntax within the struct is throwing me off. Can someone explain the init method to me like I'm 4 years old? I feel like that's the level I'm at now :)

Thanks in advance!

2 Answers

Alex Koumparos
seal-mask
.a{fill-rule:evenodd;}techdegree
Alex Koumparos
Python Development Techdegree Student 36,887 Points

Hi Kristopher,

self is definitely one of those things that takes a while to get used to. In my case, I don't think it ever sank in from hearing the concept explained, it just took lots of practice and eventually it made sense.

That said, I'm going to have a go at explaining it in a common sense way.

Let's take a look at a simple example. I'm going to use a class even though a struct would probably be a better data structure. The concept is mostly the same between the two structures, but class is what you'll see in other languages so this might look more familiar.

class Person {
    var name: String = "kristopher"
}

Here we have a super simple class that defines a Person. We can create an instance by doing something like:

let first_person = Person()

This will create an instance of Person and give it the name 'kristopher'. We can change that value by accessing the name property:

first_person.name = "alice"

Obviously, we don't always want to create an instance of a class and then manually change its properties. Most of the time we want to instantiate the object with it having the intended properties right away.

This is where initialisers come in. An Initialiser is basically just a method but with the special feature that it is called as soon as a new object is created. This means we can specify as parameters to this method the properties we want to set up when a new instance is created.

Let's add an initialiser so we can specify the name when we create an instance:

class Person {

    var name: String

    init(name: String) {
        self.name = name
    }
}

Now that we have an initialiser we have to specify a name when we call Person(), so creating a new Person looks like this:

second_person = Person(name: "bob")

Now we've introduced self into this mix. The reason that self exists is so that you can access instance-level properties from the methods inside the instance.

It's obvious how we would do that from outside the instance. If we want to access the name property on the second_person instance, we can write:

second_person.name

But inside the instance, at least at compile time, we don't know what the identity of that instance is, so we can't write second_person.name inside a method. The job of self is to be a stand-in for whatever that instance's identity is. So we can access self.name from anywhere in the instance.

Some languages, like Python, force you to be explicit like this and always use self when accessing these properties. Swift lets you be a bit lazy, and will only make you use self when a method has its own name that conflicts with an instance-level name. We see that we have this exact situation with our init: it has its own parameter called name, so we use self to distinguish the variable in the instance from the variable in the method:

self.name = name // left is the instance, right is the method

But if we create a method that doesn't have a conflicting property, we can drop the self:

class Person {

    var name: String

    init(name: String) {
        self.name = name
    }

    func sayHello() {
        print("Hello, \(name)")
    }
}

Our sayHello method doesn't have a parameter called name so in the print statement we could write \(self.name), but because Swift knows which name we are referring to, it lets us just write \(name).

Hope that helps!

Cheers

Alex

Kristopher Wood
seal-mask
.a{fill-rule:evenodd;}techdegree
Kristopher Wood
iOS Development Techdegree Student 5,552 Points

Alex, you rock! Thank you so much. I really appreciate it. When I start making money as a developer, I'll send you a kickback Cheers

Joshua Howard
Joshua Howard
12,798 Points

Thanks for that explanation. I actually struggled with knowing the real purpose of init for a while.

Just wanted to say that you guys are amazing here at TreeHouse. I'm a Kin-esthetic learner, and when I'm struggling with a concept, I can always catch on by either applying the knowledge directly here, or someone will generously explain it like i'm 5 years old.

Josue Gisber
PLUS
Josue Gisber
Courses Plus Student 9,332 Points

To help you see what Alex said "But if we create a method that doesn't have a conflicting property, we can drop the self:", here is an example:

class Person {
    var name: String

     // assigned different name in the init method
    init(firstName: String) {
        name = firstName
    }
}

let person = Person(firstName: "Ian")

As you can see, I'm using in the init method a different name for the property (firstName) and I'm assigning it to the store property name = firstName. Showing that when there's is not conflict in property name, no need for self keyword.