Day 8 - 100 Days of Swift

3 minute read

Structs (part 1)

Day 8 is about structs. You look at creating your own structs, with their own properties. You look at computed properties and property observers. You look at methods and mutating methods. And you look at a few of the built in methods on String and Array.

One way to make your own custom type in Swift is to make a struct, short for structure. They can have their own properties of various types:

1
2
3
4
5
struct Office {
    var street: String
    var buildingNumber: Int
    var employees: [Employee]
}

They can also have computed properties that run some code to figure out their value each time they are accessed:

1
2
3
4
5
6
7
8
9
struct Office {
    var street: String
    var buildingNumber: Int
    var employees: [Employee]

    var streetAddress: String {
        return "\(buildingNumber) \(street)"
    }
}

If you need to run some code either before or after a value of a property is changed, you can do so with property observers:

1
2
3
4
5
6
7
8
9
10
11
12
13
struct Office {
    var employees: [Employee] {
        willSet {
            for employee in employees {
                employee.notify()
            }
        }
        didSet {
            print("We've now got \(employees.count) people on staff")
        }
    }
}

Your custom structs can also have methods, which are called with dot syntax on an instance of the struct:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct Office {
    var employees: [Employee]

    func close(for holiday: String) {
        print("We're closing for \(holiday)")
    }
}

let theOffice = Office(employees: officeEmployees)
let raceDay = """
Michael Scott's
Dunder Mifflin Scranton
Meredith Palmer Memorial
Celebrity Rabies Awareness
Pro-Am Fun Run Race
For The Cure
"""
theOffice.close(for: raceDay)

Because structs are value types, if an instance of your struct is declared as a constant, it means all of that struct’s properties are also constant, even if they are defined as variables. Swift handles this by requiring you to mark the function as mutating if it modifies one of the struct’s properties:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct Office {
    var address: String
    var employees: [Employee]

    mutatuing func changeAddress(to newAddress: String) {
        address = newAddress
    }
}

let theOffice = Office(address: "1725 Slough Avenue",
                       employees: officeEmployees)

theOffice.changeAddress(to: "Somewhere else")
// Doesn't work, won't compile.

var otherOffice = Office(address: "123 Anytown St.",
                         employees: otherOfficeEmployees)
otherOffice.changeAddress(to: "124 Anytown St.")
// This works, other office moved over one building.

Strings have some handy built-in methods:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let quote = "'You miss 100% of the shots you don't take - Wayne Gretzky' - Michael Scott"

print(quote.count)
// 75

print(quote.hasPrefix("100"))
// false

print(quote.firstIndex(of: "%")!.encodedOffset)
// 13

print(quote.uppercased())
// 'YOU MISS 100% OF THE SHOTS YOU DON'T TAKE - WAYNE GRETZKY' - MICHAEL SCOTT

And so do Arrays:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var salesmen = ["Jim", "Dwight", "Phyllis", "Stanley"]

print(salesmen.count) // 4

salesmen.append("Andy")

print(salesmen.count) // 5

salesmen.remove(at: 3)

print(salesmen.count) // 4

print(salesmen.firstIndex(of: "Dwight")!) // 1

print(salesmen.sorted())
// ["Andy", "Dwight", "Jim", "Phyllis"]

Reflections

Today again felt like another big step in the direction of actually making something useful. Being able to define your own types opens the door to object oriented programming and a whole host of design possibilities. I’m really looking forward to putting all the pieces together to build something cool!