The Basics of Object Oriented Programming in Swift 2

PreviousTable of ContentsNext
An Overview of Swift 2 Functions, Methods and ClosuresAn Introduction to Swift Subclassing and Extensions


Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book


Swift provides extensive support for developing object-oriented iOS applications. The subject area of object oriented programming is, however, large. It is not an exaggeration to state that entire books have been dedicated to the subject. As such, a detailed overview of object oriented software development is beyond the scope of this book. Instead, we will introduce the basic concepts involved in object oriented programming and then move on to explaining the concept as it relates to Swift application development. Once again, whilst we strive to provide the basic information you need in this chapter, we recommend reading a copy of Apple’s The Swift Programming Language book for more extensive coverage of this subject area.

What is an Object?

Objects (also referred to as instances) are self-contained modules of functionality that can be easily used, and re-used as the building blocks for a software application.

Objects consist of data variables (called properties) and functions (called methods) that can be accessed and called on the object or instance to perform tasks and are collectively referred to as class members.

What is a Class?

Much as a blueprint or architect's drawing defines what an item or a building will look like once it has been constructed, a class defines what an object will look like when it is created. It defines, for example, what the methods will do and what the properties will be.


Declaring a Swift Class

Before an object can be instantiated, we first need to define the class 'blueprint' for the object. In this chapter we will create a bank account class to demonstrate the basic concepts of Swift object oriented programming.

In declaring a new Swift class we specify an optional parent class from which the new class is derived and also define the properties and methods that the class will contain. The basic syntax for a new class is as follows:

class NewClassName: ParentClass {
   // Properties
   // Instance Methods
   // Type methods
}

The Properties section of the declaration defines the variables and constants that are to be contained within the class. These are declared in the same way that any other variable or constant would be declared in Swift.

The Instance methods and Type methods sections define the methods that are available to be called on the class and instances of the class. These are essentially functions specific to the class that perform a particular operation when called upon and will be described in greater detail later in this chapter.

To create an example outline for our BankAccount class, we would use the following:

class BankAccount {

}

Now that we have the outline syntax for our class, the next step is to add some instance properties to it.

Adding Instance Properties to a Class

A key goal of object oriented programming is a concept referred to as data encapsulation. The idea behind data encapsulation is that data should be stored within classes and accessed only through methods defined in that class. Data encapsulated in a class are referred to as properties or instance variables.

Instances of our BankAccount class will be required to store some data, specifically a bank account number and the balance currently held within the account. Properties are declared in the same way any other variables and constants are declared in Swift. We can, therefore, add these variables as follows:

class BankAccount {
    var accountBalance: Float = 0
    var accountNumber: Int = 0
}

Having defined our properties, we can now move on to defining the methods of the class that will allow us to work with our properties while staying true to the data encapsulation model.

Defining Methods

The methods of a class are essentially code routines that can be called upon to perform specific tasks within the context of that class.

Methods come in two different forms, type methods and instance methods. Type methods operate at the level of the class, such as creating a new instance of a class. Instance methods, on the other hand, operate only on the instances of a class (for example performing an arithmetic operation on two property variables and returning the result).

Instance methods are declared within the opening and closing braces of the class to which they belong and are declared using the standard Swift function declaration syntax.

Type methods are declared in the same way as instance methods with the exception that the declaration is preceded by the class keyword.

For example, the declaration of a method to display the account balance in our example might read as follows:

class BankAccount {

    var accountBalance: Float = 0
    var accountNumber: Int = 0

    func displayBalance()
    {
       println("Number \(accountNumber)")
       println("Current balance is \(accountBalance)")
    }
}

The method is an instance method so it is not preceded by the class keyword.

When designing the BankAccount class it might be useful to be able to call a type method on the class itself to identify the maximum allowable balance that can be stored by the class. This would enable an application to identify whether the BankAccount class is suitable for storing details of a new customer without having to go through the process of first creating a class instance. This method will be named getMaxBalance and is implemented as follows:

class BankAccount {

    var accountBalance: Float = 0
    var accountNumber: Int = 0

    func displayBalance()
    {
       println("Number \(accountNumber)")
       println("Current balance is \(accountBalance)")
    }

    class func getMaxBalance() -> Float {
        return 100000.00
    }
}

Declaring and Initializing a Class Instance

So far all we have done is define the blueprint for our class. In order to do anything with this class, we need to create instances of it. The first step in this process is to declare a variable to store a reference to the instance when it is created. We do this as follows:

var account1: BankAccount = BankAccount()

When executed, an instance of our BankAccount class will have been created and will be accessible via the account1 variable.

Initializing and Deinitializing a Class Instance

A class will often need to perform some initialization tasks at the point of creation. These tasks can be implemented by placing an init method within the class. In the case of the BankAccount class, it would be useful to be able to initialize the account number and balance properties with values when a new class instance is created. To achieve this, the init method could be written in the class as follows:

class BankAccount {

    var accountBalance: Float = 0
    var accountNumber: Int = 0

    init(number: Int, balance: Float)
    {
        accountNumber = number
        accountBalance = balance
    }

    func displayBalance()
    {
       println("Number \(accountNumber)")
       println("Current balance is \(accountBalance)")
    }

}

When creating an instance of the class, it will now be necessary to provide initialization values for the account number and balance properties as follows:

Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book

var account1 = BankAccount(number: 12312312, balance: 400.54)

Conversely, any cleanup tasks that need to be performed before a class instance is destroyed by the Swift runtime system can be performed by implementing the deinitializer within the class definition:

class BankAccount {

    var accountBalance: Float = 0
    var accountNumber: Int = 0

    init(number: Int, balance: Float)
    {
        accountNumber = number
        accountBalance = balance
    }

    deinit {
        // Perform any necessary clean up here
    }

    func displayBalance()
    {
       println("Number \(accountNumber)")
       println("Current balance is \(accountBalance)")
    }
}

Calling Methods and Accessing Properties

Now is probably a good time to recap what we have done so far in this chapter. We have now created a new Swift class named BankAccount. Within this new class we declared some properties to contain the bank account number and current balance together with an initializer and a method to display the current balance information. In the preceding section we covered the steps necessary to create and initialize an instance of our new class. The next step is to learn how to call the instance methods and access the properties we built into our class. This is most easily achieved using dot notation.

Dot notation involves accessing an instance variable, or calling an instance method by specifying a class instance followed by a dot followed in turn by the name of the property or method:

classInstance.propertyName
classInstance.instanceMethod()

For example, to get the current value of our accountBalance instance variable:

var balance1 = account1.accountBalance

Dot notation can also be used to set values of instance properties:

account1.accountBalance = 6789.98

The same technique is used to call methods on a class instance. For example, to call the displayBalance method on an instance of the BankAccount class:

account1.displayBalance()

Type methods are also called using dot notation, though they must be called on the class type instead of a class instance:

ClassName.typeMethod()

For example, to call the previously declared getMaxBalance type method, the BankAccount class is referenced:

var maxAllowed = BankAccount.getMaxBalance()

Stored and Computed Properties

Class properties in Swift fall into two categories referred to as stored properties and calculated properties. Stored properties are those values that are contained within a constant or variable. Both the account name and number properties in the BankAccount example are stored properties.

A calculated property, on the other hand, is a value that is derived based on some form of calculation or logic at the point at which the property is set or retrieved. Computed properties are implemented by creating getter and optional corresponding setter methods containing the code to perform the computation. Consider, for example, that the BankAcccount class might need an additional property to contain the current balance less any recent banking fees. Rather than use a stored property, it makes more sense to use a computed property which calculates this value on request. The modified BankAccount class might now read as follows:

class BankAccount {

    var accountBalance: Float = 0
    var accountNumber: Int = 0;
    let fees: Float = 25.00

    var balanceLessFees: Float {
        get {
            return accountBalance - fees
        }
    }

    init(number: Int, balance: Float)
    {
        accountNumber = number
        accountBalance = balance
    }
.
.
.
}

The above code adds a getter that returns a computed property based on the current balance minus a fee amount. An optional setter could also be declared in much the same way to set the balance value less fees:

var balanceLessFees: Float {
    get {
        return accountBalance - fees
    }

    set(newBalance)
    {
                accountBalance = newBalance - fees
    }
}

The new setter takes as a parameter a floating point value from which it deducts the fee value before assigning the result to the current balance property. Regardless of the fact that these are computed properties, they are accessed in the same way as stored properties using dot-notation. The following code gets the current balance less fees value before setting the property to a new value:

var balance1 = account1.balanceLessFees
account1.balanceLessFees = 12123.12

Using self in Swift

Programmers familiar with other object oriented programming languages may be in the habit of prefixing references to properties and methods with self to indicate that the method or property belongs to the current class instance. The Swift programming language also provides the self property type for this purpose and it is, therefore, perfectly valid to write code which reads as follows:

class MyClass {
    var myNumber = 1

    func addTen() {
        self.myNumber += 10
    }
}

In this context, the self prefix indicates to the compiler that the code is referring to a property named myNumber which belongs to the MyClass class instance. When programming in Swift, however, it is no longer necessary to use self in most situations since this is now assumed to be the default for references to properties and methods. To quote The Swift Programming Language guide published by Apple, “in practice you don’t need to write self in your code very often”. The function from the above example, therefore, can also be written as follows with the self reference omitted:

func addTen() {
    myNumber += 10
}

In most cases, use of self is optional in Swift. That being said, one situation where it is still necessary to use self is when referencing a property or method from within a closure expression. The use of self, for example, is mandatory in the following closure expression:

document?.openWithCompletionHandler({(success: Bool) -> Void in
    if success {
        self.ubiquityURL = resultURL
    }
})

It is also necessary to use self to resolve ambiguity such as when a function parameter has the same name as a class property. In the following code, for example, the first println statement will output the value passed through to the function via the myNumber parameter while the second println statement outputs the number assigned to the myNumber class property (in this case 10):

class MyClass {

    var myNumber = 10 // class property

    func addTen(myNumber: Int) {
        println(myNumber) // Output the function parameter value
        println(self.myNumber) // Output the class property value
    }
}

Whether or not to use self in most other situations is largely a matter of programmer preference. Those who prefer to use self when referencing properties and methods can continue to do so in Swift. Code that is written without use of the self property type (where doing so is not mandatory) is, however, just as valid when programming in Swift.

Summary

Object oriented programming languages such as Swift encourage the creation of classes to promote code reuse and the encapsulation of data within class instances. This chapter has covered the basic concepts of classes and instances within Swift together with an overview of stored and computed properties and both instance and type methods.


Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book



PreviousTable of ContentsNext
An Overview of Swift 2 Functions, Methods and ClosuresAn Introduction to Swift Subclassing and Extensions