100 Days of SwiftUI Day 13

100 Days of SwiftUI – Day 13 – Protocols

We’ve arrived at day 13 of the 100 Days of SwiftUI. Yesterday, we focused on classes and how to use them in our programs. Today, we had a pretty long learning session about protocols and extensions. Let’s dive in!

Creating and using protocols

Protocols allow us to ensure that classes, structs and enums conform to a set of requirements. This means that they must have at least the same properties and methods defined in the property. When a class, struct or enum must adhere to a protocol, we say that it conforms to the protocol.

protocol Person {
    var name: String { get set }
    var age: Int { get set }
    
    func printSummary()
}

struct Employee: Person {
    var name: String
    var age: Int
    var jobTitle: String
    
    func printSummary() {
        print("This employee's name is \(name) and is \(age) years old. \(name)'s job title is \(jobTitle)")
    }
}

var maverick = Employee(name: "Maverick", age: 27, jobTitle: "Software Engineer")
maverick.printSummary()

// This employee's name is Maverick and is 27 years old. Maverick's job title is Software Engineer

Opaque return types

SwiftUI provides a quite complex feature called opaque return types. While I think I understand why they are used, I’ll be sure to go over the theory on this a bit more.

In a nutshell, opaque return types allow us to make our code less complex by removing the need to specify exact return types when working with protocols. For example, instead of saying that we’ll return a specific vehicle like a bike or a car, we could just say that we’ll return some vehicle. We just don’t know which one yet or we don’t want to specify it yet. Swift will be able to determine by itself what type is expected by looking at the rest of our program.

If you want to go over opaque return types yourself, I’ll refer you to Paul’s article and video.

func getRandomNumber() -> some Equatable {
    Int.random(in: 1...6)
}

func getRandomBool() -> some Equatable {
    Bool.random()
}

Creating and using protocol extensions

Extensions let us add functions to any type, either the ones we create or the ones built into Swift. If you want to know when you should use extensions, check out Paul’s explanation.

Extensions become even more powerful when combined with protocols. When applied to a protocol, an extension automatically applies to all classes, structs and enums that conform to the protocol.

extension Collection {
    var isNotEmpty: Bool {
        isEmpty == false
    }
}

var mushroomKingdom = ["Mario", "Luigi", "Peach"]
if mushroomKingdom.isNotEmpty {
    for i in 0...2 {
        print(mushroomKingdom[i])
    }
}

SwiftUI checkpoint 8

Similarly to yesterday, after spending time learning a very important part of Swift, it’s only fitting to have a checkpoint at the end to see if we grasped the fundamentals. The challenge today:

Make a protocol that describes a building, adding various properties and methods, then create two structs, House and Office, that conform to it. Your protocol should require the following:

  1. A property storing how many rooms it has.
  2. A property storing the cost as an integer (e.g. 500,000 for a building costing $500,000.)
  3. A property storing the name of the estate agent responsible for selling the building.
  4. A method for printing the sales summary of the building, describing what it is along with its other properties.

My solution is perhaps a bit simple, but it does cover all the bases. I’ve tried using an extension for the Building protocol as well, but it seemed unnecessary for just the single printSummary function.

import Cocoa
import Foundation

protocol Building {
    var rooms: Int { get set }
    var cost: Int { get set }
    var estateAgent: String { get set }
    
    func printSummary()
}

struct House: Building {
    var rooms: Int
    var cost: Int
    var estateAgent: String
    
    func printSummary() {
        print("This house has \(rooms) rooms, costs \(cost) and is sold by \(estateAgent).")
    }
}

struct Office: Building {
    var rooms: Int
    var cost: Int
    var estateAgent: String
    
    func printSummary() {
        print("This office has \(rooms) rooms, costs \(cost) and is sold by \(estateAgent).")
    }
}

var bark = House(rooms: 4, cost: 375000, estateAgent: "Built for Kings")
bark.printSummary()

var maverickOffice = Office(rooms: 16, cost: 1_200_000, estateAgent: "Code Bricks")
maverickOffice.printSummary()

/* This house has 4 rooms, costs 375000 and is sold by Built for Kings.
 This office has 16 rooms, costs 1200000 and is sold by Code Bricks. */

And that was it for day 13! It was a long and intensive day, but I feel like I’ve grasped most of what was taught pretty well. Paul made it clear that what we’ve learned over the past few days will really sink in when we start seeing it all come together in projects, so I’m not worried. Tomorrow, we’ll tackle optionals, nil coalescing, and checkpoint 9. We march on!

Darryl

Hi! My name is Darryl and this is my personal blog where I write about my journey as I learn programming! You'll also find articles about other things that interest me including games, tech and anime.

Post navigation

Leave a Comment

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

100 Days of SwiftUI – Day 39 – Moonshot

100 Days of SwiftUI – Day 87

100 Days of SwiftUI – Day 42

100 Days of SwiftUI – Day 36 – iExpense