Skip to content

Object Oriented Swift

28 June 2014no comments By: Thomas De Leon

Swift

Swift Logo – Apple

What is Object Oriented Programming- Using Object Oriented Swift

Now that Apple’s new programming language Swift has been unveiled, we’re going to re-visit our original article, What is Object Oriented Programming? – A Basic Explanation, and introduce some examples using Swift. Note that Swift is still a language in development, so some things may change. The goal here is not to teach Swift (a free book from Apple is available here), but to show object oriented programming basics using Swift. Keep in mind, there are many more unique and useful things that are part of the Swift language, which are not shown here (watch for future posts on these).

Be sure to check out the list of books and online resources which may be helpful in learning OOP concepts. And of course feel free to try out the code snippets in a Playground!

It’s all about Objects

As the name would imply, object oriented programming is all about, big surprise… objects. But what does that really mean? Let’s look at some real-world examples using object oriented Swift.

Describing an Object

Imagine an object that most people can relate to, a car. How can we describe a car? Well, it has attributes such as the color, make, model, year, mileage, and vin. Each of these attributes make each car what it is. In OOP, attributes, the features that describe an object, are called properties.

A Car class would be declared as follows, with the given properties. Note that in Swift, properties are required to be initialized to a value- this may be different in other languages.

class Car {
    var color:String = “”
    var make:String = “”
    var model:String = “”
    var year:Int = 0
    var mileage:Int = 0
    var vin:Int = 0
}

Actions of an Object

The next question is, what are the actions a car can do, or can be done to the car? Let’s take some of the obvious ones:

  • Turn the car on
  • Turn the car off
  • Accelerate
  • Brake

In OOP, these actions, are called methods. They allow the objects to do things, and as you’ll see next, also provide a way to manipulate the properties of the object. In Swift, the methods are simply declared within the braces of the class, and are like any other function:

class Car {
    var color:String = “”
    var make:String = “”
    var model:String = “”
    var year:Int = 0
    var mileage:Int = 0
    var vin:Int = 0

    func turnOn() {
        // turn on the car here
    }
    func turnOff() {
        // turn off the car here
    }
    func accelerate() {
        // start moving
    }
    func brake() {
        // slow down
    }
}

Changing and Reading the Description

When you buy a car, it has all the properties we described above (color, make, model, etc.) already defined. The car is painted, was made by a certain manufacturer, and is of a certain mode type, and so on. Some of those are fixed, for example if the car was made by Toyota, it’s going to be a Toyota for the rest of it’s life. But what about something like the color? A few years after you buy the car, you may decide you’re tired of black and want it repainted to green. In object oriented programming, we call this setter methods, which are just special methods for setting properties on an object. Typically, they are just the property name prepended with “set”, so in our case, it would be setColor. The opposite can also be done, let’s say we get stopped for a speeding ticket, and the officer wants to get the VIN number. You would read the VIN through a getter method, which typically have ‘get’ prepending the property, so the officer would be using would be getVin.

class Car {
    var color:String = “” {
    set {
        self.color = newValue
    }
    }
    var make:String = “”
    var model:String = “”
    var year:Int = 0
    var mileage:Int = 0
    var vin:Int = 0 {
    get {
       return self.vin
    }
    }
}

These examples are not particularly useful in application, as in Swift (and in many languages), the setter and getter methods are automatically defined. For example, in this case, if all that is being done is setting the new color or reading the value of the VIN number, defining these methods is unnecessary. The same thing can be accomplished by using what is known as dot notation. The equivalent would be (assuming a Car object called myCar and an Int variable vinNumber):

var myCar = Car()
var vinNumber = 0 // declare an Int variable

myCar.color = “green” // same as myCar.setColor(“green”)
vinNumber = myCar.vin // same as vinNumber = myCar.getColor()

However, getter and setter methods can be very useful when you need to accomplish several things when setting a property (such as setting another property), or when the value when reading needs to be calculated each time. For example, you could build logic into the setter method for the mileage property to always increment the existing mileage:

class Car {

// Other properties not shown

    var mileage {
    set {
        self.mileage += newValue
    }
    }
}

var miles = myCar.mileage // Current miles = 300
myCar.mileage(200) // Take a 200 mile road trip
miles = myCar.mileage // Current miles = 500

Creating Objects

Now that we have properties, methods, and ways to read or set/change the properties through setter and getter methods, you may be asking, how do we create the objects in the first place?

Object Oriented Programming Constructors

The answer introduces another term in OOP, called a constructor. A constructor is a special method which creates an object. After you’ve created an object, you have an instance of it. This process is called instantiation.

Example

To illustrate this, lets go back to the car example. We are at the factory, and we instantiate our car by using a constructor method to create it. This special method takes inputs for the model, color, and VIN number, and outputs a brand new car. If you recall though, we had more properties than those, what about the make, year, and mileage?

In our example, if we are at a Toyota factory, the cars produced will always be Toyota, and the mileage will always be zero. The year will change, but will always match the current year. While we could simply pass those into our constructor, since those values are (mostly) fixed, we can simply set them in the constructor itself. This way we can be sure that every new car created with this constructor will have the make set to Toyota, the mileage to zero, and the year will always be current. The idea of setting properties when an object is created is called initializing them.

In Swift, there is a special method called init, which is used to initialize properties to default values on instantiation. This is often known as a “default constructor” in other languages.

class Car {
    var color:String
    let make:String
    let model:String
    let year:Int
    let vin:Int
    var mileage:Int
    init() {
        make = “Toyota”
        model = “Matrix”
        year = 2014
        color = “Green”
        mileage = 0
    }
}

However, in Swift, when you are setting property values to default and they will always be the same initial value, it is recommended to simply assign the values directly, which has the same effect. This makes the mode more concise and easier to read:

class Car {
    var color = "Green"
    let make = "Toyota"
    let model = "Matrix"
    let year = 2014
    let vin = 1234
    var mileage = 0
}

But the code above will always initially set the color to green, the model to matrix, the year to 2014, the vin to 1234, and the mileage to 0. It’s good that all properties are being set, however the only ones which should always be the same initially are the make and mileage. The others will be different depending on what car is being made. We could of course just set these properties after creating the Car object, but that seems clunky, and some of the properties are meant to be constants which can’t be changed after initialization (let).

When you have some options that need to be specified when an object is created, these can be added to a constructor. In Swift, this means adding parameters to the init() function:

class Car {
    var color:String
    let make:String = “Toyota”
    let model:String
    let year:Int
    let vin:Int
    var mileage:Int = 0

    init(model:String, color:String, vin:Int) {
        self.model = model
        self.color = color
        self.vin = vin
        self.year = currentYear() // some function to get the current year
   }
}

To create the Car object:

var myCar = Car(model:”Matrix” color:”Green” vin:1234)

// {color “Green” make “Toyota” model “Matrix” year 2014 vin 1234 mileage 0}

Note that you can have multiple constructors (initializers). For example, our particular factory may not only be dedicated to making Toyotas, but also only makes the Matrix model. So we could define an additional initializer for our particular factory which always sets the model of the car to Matrix:

class Car {
    var color:String
    let make:String = "Toyota"
    let model:String
    let year:Int
    let vin:Int
    var mileage:Int = 0
    init(model:String, color:String, vin:Int) {
        self.model = model
        self.color = color
        self.vin = vin
        self.year = currentYear() // some function to get the current year
    }
    init(color:String, vin:Int) {
        self.model = "Matrix"
        self.color = color
        self.vin = vin
        self.year = currentYear() // some function to get the current year
    }
}

var myCar = Car(color:”Green” vin:1234)

// {color “Green” make “Toyota” model “Matrix” year 2014 vin 1234 mileage 0}

In fact, we can simplify this even more, by simply calling the original initializer. This is known as a convenience initializer in Swift, which is tagged with the keyword convenience:

class Car {
    //property declarations

    init(model:String, color:String, vin:Int) {
        self.model = model
        self.color = color
        self.vin = vin
        self.year = currentYear() // some function to get the current year
    }
    convenience init(color:String, vin:Int) {
        let model = "Matrix"
        self.init(model:model, color:color, vin:vin)
    }
}

Constructor Abilities

Note that a constructor can take all, some, or no properties as inputs, but will always create an object as output. For one taking no inputs, there you would initialize the properties to some value (which is always good practice, and as we saw in Swift, required), expected to be changed at some later point. The other piece that all constructors do is allocate memory. This differs from language to language, but will always do the actual creating of the object. Also, there are methods which do the opposite, called destructors, which destroy the object. They are important because they deallocate any memory allocated in the constructor. Often, this is all they will do, but other code can be added to them which will be executed when the object is destroyed.

In Swift, destructors are not required, as the memory deallocation is abstracted away and done automatically. However, they are available and known as “deinitializers”, to perform any cleanup that needs to be done just prior to actual deallocation of the object. Deinitializers are optional, and there can be one at most in a class.

In our car example, before we send it to the junkyard, we might want to un-register the vehicle’s license and cancel the insurance:

class Car {
    //properties
    init(model:String, color:String, vin:Int) {
        // init code
    }

    deinit {
        unRegisterLicense() // some function that un-registers the license
        cancelInsurance() // some function that cancels the insurance policy
    }
}

How can this save you time?

So far, you may see how this can help organize how you store data (in fact it can be comparable to how you’d store data in fields and tables in a relational database), but you may wonder how this can help you save time?

Up to now, you may have just been thinking of our car as a typical sedan. Ok, lets change the manufacturer now to Volvo. Volvo makes cars, trucks and buses, so what do we do now? No problem, you say! We can just create bus and truck objects just like we did for cars, and we’re all set.

Yes, that works, but it’s not a good solution. All three types share common properties, and even methods. But it means you’d have to write those three times, to do the exact same thing.

An Efficient Solution

The better solution, and what OOP is all about, is to create another object, which holds all the properties and methods that are common between cars, trucks, and buses. Here is where we’ll change terms, and instead of calling these objects, we’ll now call them classes. Classes are objects when they have been created, but this is a better term because it also refers to them when they haven’t been created yet.

Back to our example. So now we have a class called vehicle, with all the properties and methods common to our three types of vehicles. This is called the base class, and the three vehicles are it’s subclasses. What’s important to note is that those common properties and methods only need to be defined in the parent class level. The children automatically have access to these, and so defining them there is not necessary. This concept is called inheritance.

With this  model, you would typically never instantiate a generic vehicle directly, but instead would instantiate one of it’s three subclasses. Of course this may not always be the case, and there may be circumstances where you do want to use a generic parent- for example if you were describing a search for a vehicle, but the type was not known. In Swift, we might define our vehicle base class like this. Notice that the properties would be common to both Cars, Trucks, and Buses:

class Vehicle {
    var color:String
    let axles:Int
    let make:String = “Volvo”
    let model:String
    let year:Int
    let vin:Int
    var mileage:Int = 0

    init(model:String, color:String, vin:Int, axles:Int) {
        self.model = model
        self.color = color
        self.vin = vin
        self.year = currentYear() // some function to get the current year
    }
}

Object Oriented Programming (OOP) Diagram

Subclasses

In the subclasses, we only need to define the things that are unique to them. For example, for a truck the maximum amount of cargo is important, so this could be a property, and a bus may have a method to loadPassengers or unloadPassengers.

Remember the axles property defined in the base Vehicle class? This is the number of axles on the vehicle. Let’s assume that Cars always have two, and Trucks and Buses always have three. We can use convenience and designated constructors (initializers in swift) to enforce this rule. This way when the vehicles are created, we can keep someone from doing something ridiculous like adding a car with ten axles or a truck with zero. Also note in this Swift example, the addition of the : Vehicle. This indicates that the Bus class is a subclass of the Vehicle class, and should inherit properties and methods.

class Bus : Vehicle {
    var currentPassengers:Int
    var maxPassengers:Int {
    get {
        return maxOccupants - 1 // subtract the driver
    }
    }
    
    init(model:String, color:String, vin:Int, maxOccupants:Int) {
        self.currentPassengers = 0
        let axles = 3
        super.init(model:model, color:color, vin:vin, axles:axles, maxOccupants:maxOccupants)
    }
    
    func loadPassengers(passengers:Int)->Bool {
        let newNumPassengers = currentPassengers + passengers
        if (newNumPassengers <= maxPassengers) {
            currentPassengers = newNumPassengers
            return true
        }
        else {
            return false
        }
    }
    func unloadPassengers(passengers:Int)->Bool {
        if (passengers > currentPassengers) {
            return false
        }
        else {
            currentPassengers -= passengers
            return true
        }
    }
}

Here, you can see we set the number of axles to three (let’s assume all buses we make have three axles), and then call the init on our parent Vehicle class. So in the init method for this class we set properties defined at our level, then we pass on everything else which is inherited up to the base class.

init(model:String, color:String, vin:Int, maxOccupants:Int) {
    self.currentPassengers = 0
    let axles = 3
    super.init(model:model, color:color, vin:vin, axles:axles, maxOccupants:maxOccupants)
}

Additionally, we’ve added methods to load and unload passengers, while checking to make sure we don’t go over the max capacity (returning false if we can’t take any more people).

func loadPassengers(passengers:Int)->Bool {
    let newNumPassengers = currentPassengers + passengers
    if (newNumPassengers <= maxPassengers) {
        currentPassengers = newNumPassengers
        return true
    }
    else {
        return false
    }
}
func unloadPassengers(passengers:Int)->Bool {
    if (passengers > currentPassengers) {
        return false
    }
    else {
        currentPassengers -= passengers
        return true
    }
}

Also imagine that we started to produce other types of vehicles, the inheritance concept really makes things easier to add them, as we simply need to define the properties which are not already covered by the common vehicle class.

In OOP, you will sometimes have classes that are not intended to be used directly (such as our vehicle class in this example), but instead simply exist as a common parent, which is known as an abstract class. In these cases, it is meant for the subclasses to be used only. In other cases, the parent and subclasses can be used. Subclassing can also be a way for you to extend an existing class that you would like to add functionality to.

Note that in some languages, an abstract class is an explicit thing which can be defined and is enforced. In Swift, there is not an explicit way of making a class abstract- however this can be achieved by making the base class a protocol, and then having subclasses inherit from them (as protocols cannot be directly instantiated). In other languages which have no abstract concept, you can still use this in your design by documenting that a base class is not intended to be instantiated.

Summary

Hopefully this has helped with a basic understanding of Object Oriented Programming concepts, for those unfamiliar. It is a great concept to learn, and can make your programming much more robust and faster to develop. Also, these concepts are pretty general and apply to many different object oriented languages.

To summarize, here are some of the main object oriented programming concepts:

  • Objects (classes) consist of properties and methods
  • Constructors are used to create objects, destructors are used to destroy them.
  • Subclassing and inheritance can help you save time by re-using and better organizing your code

Definitions

abstract class - a base class which is meant to store common properties and methods for subclasses to inherit, and is not meant to be instantiated directly

class – another term for an object; contains properties and methods

constructor – a special method which creates an object and initializes its properties

destructor – a special method which destroys an object

getter method – a special method which gets the value of a property

initializing – setting properties to their initial values when a class is instantiated

instantiation – the process of creating an instance of a class

methods – functions which are actions that belong to an object

base class – the “main” class where other classes inherit properties and methods from

properties – attributes (variables) which describe an object

setter method – a special method which sets the value of a property

subclass – classes which inherit properties and methods from a parent class; it can also define it’s own properties and methods

Online Resources

Books

Spread The Love, Share Our Article

  • Delicious
  • Digg
  • Newsvine
  • RSS
  • StumbleUpon
  • Technorati
  • Twitter

Related Posts

Comments

There are no comments on this entry.

Trackbacks

There are no trackbacks on this entry.

Add a Comment

Required

Required

Optional