Leave a rating/review
Notes: 40. Classes
Update Notes: The student materials have been reviewed and are updated as of October 2021.
Classes are a lot like Structures. They have properties, methods, and initializers. However, Classes are reference types, instead of value types. In this part of the episode, you’ll get an idea of how that affects your code.
In this episode, we’ll cover the basics of classes in Swift. And we’ll do that by starting with a structure, which you should have a handle on by now. Then, we’ll convert it to a class, and compare the results.
At the top of this Playground page I already have a simple Actor struct set up for you.
struct Actor {
let name: String
var filmography: [String] = []
}
It has two properties: a constant String to represent the Actor’s name, and a variable array of Strings to act as their filmography. For this exercise, that’ll just be an array of film titles. And that’s all we need to represent an actor like Zoe Saldana.
Actor(name: "Zoe Saldana", filmography: ["<#T##[String]#>"])
I’ll start her filmography off with Guardians of the Galaxy.
…"Guardians of the Galaxy"])
You may remember from the earlier episode on structures, if I want to change any of Zoe’s properties, like adding to her filmography, I’ll have to represent her with a variable–not a constant. I’ll call that variable “G-O-T-G Star”.
var gotgStar = Actor(…
And now, I can add Avatar to her filmography.
gotgStar.filmography.append("Avatar")
Another variable name that describes Zoe is “Star Trek Star”. Assigning “Guardians of the Galaxy Star” to startTrekStar represents that equivalence.
var starTrekStar = gotgStar
Go ahead and add “Star Trek” to her filmography.
starTrekStar.filmography.append("Star Trek")
All of these films so far are first entries in franchises. Let’s add a method that will allow an Actor to sign on for franchise sequels, using the name of the franchise.
func signOnForSequel(franchiseName: String) {
}
It’ll have to be marked as mutating because it will modify the filmography.
mutating …
And the way it will do that is by appending “Upcoming sequel”, with the franchise name.
filmography.append("Upcoming \(franchiseName) sequel")
Zoe is also “Avatar Star”, so let’s make a third variable, assigning it starTrekStar’s value.
var avatarStar = starTrekStar
And then, because at this point, Zoe’s filmography is made up completely of movies with the same names as their franchises, you can loop through avatarStar’s filmography, and sign her on for a sequel to each one.
for franchiseName in avatarStar.filmography {
avatarStar.signOnForSequel(franchiseName: franchiseName)
}
Alright, let’s check out avatarStar’s filmography!
avatarStar.filmography
Zoe’s real filmography is a lot longer than that, but this will do for this exercise. And now, because starTrekStar and gotgStar are also Zoe Saldana, they should have the same filmography, right?
starTrekStar.filmography
Wrong!
gotgStar.filmography
Even more wrong!
We are going to get this sorted out, but let’s review why you’re seeing this behavior. As we’ve gone over, structures are value types, which means that everything their instances contain is copied on assignment.
In this example, imagine that you create person with an initializer, providing the values “Ray” and “Wenderlich”. And then you assign person to another variable: instructor. Kind of like what you’re coding in the exercise: you give the same person different variable names.
But the two instances you have are now totally independent. If you were to change person’s name to “Bob Wenderlich”, instructor would still be “Ray Wenderlich.”
What you probably want instead, looks more like this. Both person and instructor should reference the same instance of a Person type. As as you can see in diagram, that can done with a class instance–otherwise known as an “object”. Let’s convert our Actor value type to be a reference type!
The first change is to use the keyword class instead of struct.
class Actor {
Then, the errors that appear will help us complete the transformation. The first one says Actor doesn’t have an initializer. Which is true! Classes do not get an automatically-generated initializer like structures do.
That’s not a big deal, though. Initializers are fairly similar to methods in syntax, and you’ve got a good handle on those. Start a new initializer with the keyword init
init
And then add a parameter list that includes both properties and their types, and wrap it up with a pair of curly braces
init(name: String, filmography: [String]) {
}
Within the initializer, you need to assign the parameters to the class’s properties. You do that by saying self.name = name
init(name: String, filmography: [String]) {
self.name = name
The “self”, here, is referring to the specific instance of this class that will be created by the initializer. Do the same thing for filmography:
self.name = name
self.filmography = filmography
}
Then, we’re told, somewhat unclearly, that the keyword mutating is not used in classes. You can just delete it.
❌mutating❌ func…
You’re still performing a mutation with that method, but only to the filmography. Remember, with a structure, when you mutate any of its properties, you’re actually making an entirely new structure, only based on the original. That is not true with classes.
You still can’t mutate constant properties of a class instance, like an Actor’s name. But you can change anything marked with var, and Swift won’t consider you to be working with a new object. It’s still the old object, but with new values. And that applies even if your object is declared as a constant. Let’s try that!
Now that you know that you can, change the first two of these “star” variables, to be constants.
let gotgStar …
…
let starTrekStar …
Now, we’ve got an Actor class, and we’re definitely making mutations to the class instances. But they’re all to the same actor’s filmography now.
avatarStar.filmography
starTrekStar.filmography
gotgStar.filmography
To me, avatarStar, starTrekStar, and gotgStar should all be referencing the same Zoe Saldana. So for modeling this particular Actor type, I think a class is the way to go.
Let’s sum up what you’ve learned about structures and classes in the past few episodes.
- Structures are value types, and classes are reference types.
- An instance of a structure is conceptually a value. Class instances are objects with identity.
- Structures copy their values when used in a new place, but classes share their data.
- Structures are completely immutable when declared as constants, while class properties remain mutable.
As you get more experience, you’ll gain a firmer grasp on classes, structures, and their different capabilities.
After you’ve completed the next course in this learning path, Your Second iOS App, we’ll have another Swift course waiting for you that will take a much closer look at not only structs and classes, but one more named type called an enumeration.
But before any of that, I’ve got one final challenge for you!