1️⃣Classes

Fall 2023 | Richie Sun

In Swift, there are two ways that we can build complex data types beyond the given basic types like Int, Float, and String. Classes are one such way that we can build some of these complex data types that we'll see later on in the UIKit framework as well as many other Swift packages.

Defining a Class

If you have taken CS 1110 or 2110, then classes may already be familiar to you, but essentially; Classes can be thought of as blueprints. Within these blueprints, there are many different specifications and properties, for what we want the objects of the class to possess.

Thus, under the same analogy, objects are the houses that are built from the class blueprints

  • Class = Blueprint

  • Object = House built from blueprint

For example, let's suppose we define the following class for a house below:

class House {
    var color: String
    var material: String
    var owner: String

    init(color: String, material: String, owner: String) {
        self.color = color
        self.material = material
        self.owner = owner		
    }

    func paintHouse(color: String) {
	self.color = color
    }
}

Within the house class, there are many properties such as color, material, and owner along with their specified type, as well as any methods associated with the class.

Instantiation and Objects

However, with properties alone, the class is not complete, we need to also define an initializer as shown above. Essentially what the initializer does, is that it instantiates an object of the class.

In the code chunk above, notice the keyword self. The self keyword is used to represent an instance (or object) of the given class. In this case, the initializer creates the instance of the House class, which is then represented by the self keyword. Then, the properties color, material, and owner are initialized through self.

As shown below, the initializer is a function that is the same name as that of the Class, where we are able to pass in the desired values for the specified properties.

let blueHouse = House(color: "blue", material: "brick", owner: "Vin")
let redHouse = House(color: "red", material: "wood", owner: "Richie")

blueHouse and redHouse are both objects (or instances) of the same House Class

Now that we have an instance of that class we can then access its properties and call any class methods as shown below:

let house = House(color: "white", material: "wood", owner: "Reade")
house.color // white
house.paintHouse(color: "blue")
house.color // blue

Inheritance

Classes can also be built based on other classes, this is known as class inheritance. This is a prominent technique that we'll see used extensively throughout UIKit, even in the most basic apps, so it's something we will need to eventually get familiar with.

Lets move back to our scenario with the House class that has properties color, material, and owner, and methods like the initializer and paintHouse method.

class House {
    var color: String
    var material: String
    var owner: String

    init(color: String, material: String, owner: String) {
        self.color = color
        self.material = material		
	self.owner = owner		
    }

    func paintHouse(color: String) {
	self.color = color
    }
}

Supposed we wanted to define a new class to represent a TreeHouse, which includes all the properties that the House object does, but also includes new properties like treeType and slideColor.

Of course, it may seem logical at first to take all the code defined in the House class and copy it over to the TreeHouse, but this repetition of code may come back to bite us later on when we want to change the House class and also want the same changes to TreeHouse. We would have to change the same code twice!

Luckily, Swift offers a smarter solution with class inheritance: We can define the TreeHouse class based on our existing House class

class TreeHouse: House {
    // Class implementation here
}

The colon above is what establishes this inheritance, it indicates that TreeHouse is a subclass of House, or House is the superclass of TreeHouse; thus, TreeHouse will inherit all properties and methods from the House class.

let treeHouse = TreeHouse(color: "red", material: "wood", owner: "Tiffany")
treeHouse.color // red
treeHouse.paintHouse(color: "blue")
treeHouse.color // blue

However, we are not quite there yet, we also want to add the properties treeType and slideColor, and also change the paintHouse method so that we also have a color option to paint the slide.

class TreeHouse: House {
    var treeType: String
    var slideColor: String
		
    init(color: String, material: String, owner: String, treeType: String, slideColor: String) {
        self.treeType = treeType
	self.slideColor = slideColor
        super.init(color: color, material: material, owner: owner)
    }
}

Notice that we did not redefine any of the properties that already exist in House since they are inherited. In the initializer, notice a new keyword super. The keyword super represents the superclass, where in this case we are calling the initializer from the superclass House, which initializes the original 3 properties.

Now let us change the paintHouse function:

override func paintHouse(color: String, slideColor: String) {
    self.color = color
    self.slideColor = slideColor
}

Notice the keyword override. In Swift, override indicates that a method is implemented in the superclass, but we want to change it for the subclass. Thus, if we want to redefine the paintHouse function to apply for TreeHouse, we need to β€œoverride” the existing method

If we don't use override Swift won't let us change a method we got from our superclass.

Last updated