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 trialKristopher Wood
iOS Development Techdegree Student 5,552 PointsCan 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
Python Development Techdegree Student 36,887 PointsHi 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
Josue Gisber
Courses Plus Student 9,332 PointsTo 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.
Kristopher Wood
iOS Development Techdegree Student 5,552 PointsKristopher Wood
iOS Development Techdegree Student 5,552 PointsAlex, 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
12,798 PointsJoshua Howard
12,798 PointsThanks 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.