Day 08
Day 08 êŽë š
Structs, part one
I know some of you might be keen to charge on with todayâs new Swift learning, but hold up: you just finished learning about closures, which are a difficult topic. And you came back for more. Seriously, that deserves a lot of respect.
And I have some good news for you. First, not only will we be covering closures again in a consolidation day next week, but soon enough weâll also start putting them into practice in real iOS projects. So, even if you arenât 100% sure of how they work or why they are needed, it will all become clear â stick with it!
Anyway, todayâs topic is structs. Structs let us create our own data types out of several small types. For example, you might put three strings and a boolean together and say that represents a user in your app.
These custom types â users, games, documents, and more â form the real core of the software we build. If you get those right then often your code will follow.
As Fred Brooks, the author of the hugely influential book The Mythical Man-Month, once said, âthe programmer at witâs end... can often do best by disentangling themself from their code, rearing back, and contemplating their data. Representation is the essence of programming.â
Today you have seven one-minute videos to watch, and youâll learn how to create your own types, adding properties, methods, and more. Once youâve completed each video, there is a short piece of optional extra reading if youâre looking to get some more details, and thereâs also a short test to help make sure youâve understood what was taught.
1. Creating your own structs
1. Creating your own structs
Swift lets you design your own types in two ways, of which the most common are called structures, or just structs. Structs can be given their own variables and constants, and their own functions, then created and used however you want.
Letâs start with a simple example: weâre going to create a Sport
struct that stores its name as a string. Variables inside structs are called properties, so this is a struct with one property:
struct Sport {
var name: String
}
That defines the type, so now we can create and use an instance of it:
var tennis = Sport(name: "Tennis")
print(tennis.name)
We made both name
and tennis
variable, so we can change them just like regular variables:
tennis.name = "Lawn tennis"
Properties can have default values just like regular variables, and you can usually rely on Swiftâs type inference.
1. Creating your own structs - Additional
2. Computed properties
2. Computed properties
We just created a Sport
struct like this:
struct Sport {
var name: String
}
That has a name property that stores a String
. These are called stored properties, because Swift has a different kind of property called a computed property â a property that runs code to figure out its value.
Weâre going to add another stored property to the Sport
struct, then a computed property. Hereâs how that looks:
struct Sport {
var name: String
var isOlympicSport: Bool
var olympicStatus: String {
if isOlympicSport {
return "\(name) is an Olympic sport"
} else {
return "\(name) is not an Olympic sport"
}
}
}
As you can see, olympicStatus
looks like a regular String
, but it returns different values depending on the other properties.
We can try it out by creating a new instance of Sport
:
let chessBoxing = Sport(name: "Chessboxing", isOlympicSport: false)
print(chessBoxing.olympicStatus)
2. Computed properties - Additional
3. Property observers
3. Property observers
Property observers let you run code before or after any property changes. To demonstrate this, weâll write a Progress
struct that tracks a task and a completion percentage:
struct Progress {
var task: String
var amount: Int
}
We can now create an instance of that struct and adjust its progress over time:
var progress = Progress(task: "Loading data", amount: 0)
progress.amount = 30
progress.amount = 80
progress.amount = 100
What we want to happen is for Swift to print a message every time amount
changes, and we can use a didSet
property observer for that. This will run some code every time amount
changes:
struct Progress {
var task: String
var amount: Int {
didSet {
print("\(task) is now \(amount)% complete")
}
}
}
You can also use willSet
to take action before a property changes, but that is rarely used.
3. Property observers - Additional
- Optional: When should you use property observers?
- Optional: When should you use willSet rather than didSet?
- Test: Property observers
4. Methods
4. Methods
Structs can have functions inside them, and those functions can use the properties of the struct as they need to. Functions inside structs are called methods, but they still use the same func
keyword.
We can demonstrate this with a City
struct. This will have a population
property that stores how many people are in the city, plus a collectTaxes()
method that returns the population count multiplied by 1000. Because the method belongs to City
it can read the current cityâs population
property.
Hereâs the code:
struct City {
var population: Int
func collectTaxes() -> Int {
return population * 1000
}
}
That method belongs to the struct, so we call it on instances of the struct like this:
let london = City(population: 9_000_000)
london.collectTaxes()
4. Methods - Additional
- Optional: Whatâs the difference between a function and a method?
- Test: Methods
5. Mutating methods
5. Mutating methods
If a struct has a variable property but the instance of the struct was created as a constant, that property canât be changed â the struct is constant, so all its properties are also constant regardless of how they were created.
The problem is that when you create the struct Swift has no idea whether you will use it with constants or variables, so by default it takes the safe approach: Swift wonât let you write methods that change properties unless you specifically request it.
When you want to change a property inside a method, you need to mark it using the mutating
keyword, like this:
struct Person {
var name: String
mutating func makeAnonymous() {
name = "Anonymous"
}
}
Because it changes the property, Swift will only allow that method to be called on Person
instances that are variables:
var person = Person(name: "Ed")
person.makeAnonymous()
5. Mutating methods - Additional
- Optional: Why do we need to mark some methods as mutating?
- Test: Mutating methods
6. Properties and methods of strings
6. Properties and methods of strings
Weâve used lots of strings so far, and it turns out they are structs â they have their own methods and properties we can use to query and manipulate the string.
First, letâs create a test string:
let string = "Do or do not, there is no try."
You can read the number of characters in a string using its count
property:
print(string.count)
They have a hasPrefix()
method that returns true if the string starts with specific letters:
print(string.hasPrefix("Do"))
You can uppercase a string by calling its uppercased()
method:
print(string.uppercased())
And you can even have Swift sort the letters of the string into an array:
print(string.sorted())
Strings have lots more properties and methods â try typing string
. to bring up Xcodeâs code completion options.
6. Properties and methods of strings - Additional
7. Properties and methods of arrays
7. Properties and methods of arrays
Arrays are also structs, which means they too have their own methods and properties we can use to query and manipulate the array.
Hereâs a simple array to get us started:
var toys = ["Woody"]
You can read the number of items in an array using its count
property:
print(toys.count)
If you want to add a new item, use the append()
method like this:
toys.append("Buzz")
You can locate any item inside an array using its firstIndex()
method, like this:
toys.firstIndex(of: "Buzz")
That will return 1 because arrays count from 0.
Just like with strings, you can have Swift sort the items of the array alphabetically:
print(toys.sorted())
Finally, if you want to remove an item, use the remove()
method like this:
toys.remove(at: 0)
Arrays have lots more properties and methods â try typing toys. to bring up Xcodeâs code completion options.
7. Properties and methods of arrays - Additional