Download as pdf or txt
Download as pdf or txt
You are on page 1of 11

Object Oriented Programming in Swift

Most of Apple’s frameworks have a object-oriented architecture. Before you start digging into
iOS/MacOS development you should first understand object oriented programming and design
patterns. In this article we will go through the basic notions and design patterns in order to get
you started with app development.

Overview

Object-oriented programming (OOP) is a programming paradigm that represents the concept of


“objects” that have data fields (attributes that describe the object) and associated procedures
known as methods. Objects, which are usually instances of classes, are used to interact with one
another to design applications and computer programs.

There are 3 key aspects of object oriented programming:

Encapsulation means that objects keep their state information private. Rather than directly
manipulating an object’s data, other objects send requests to the object, in the form of messages,
some of which the object may respond to by altering its internal state.

Polymorphism means that objects of different classes can be used interchangeably. This is
especially important, as it allows you to hook up classes at a later date in ways you didn’t
necessarily foresee when those classes were first designed.

Inheritance means that objects of one class can derive part of their behavior from another (base
or parent) class. Some object-oriented languages (C++, for example, but not Swift) allow
multiple inheritance, where objects of one class can derive part or all of their behavior from
multiple independent base classes.

Classes and Objects

In object-oriented programming, a class is an extensible program-code-template for creating


objects, providing initial values for state (member variables) and implementations of behavior
(member functions, methods). In other words, a class is like a blueprint, it defines the data and
behavior of a type.

class Button {
}

The definition above creates an empty class named Button. The only thing it can do is create
new Button objects:

var button = Button()

In the example above button is an instance of the Button class.


Properties

Classes and instances can have associated values named properties.

class Square {
var length: Int = 1
}

The Square class has a length property that has a default value of 1.

In order to create squares with a different length than 1 we need to write a custom initializer.

class Square {
var length: Int = 1

init(length: Int) {
self.length = length
}
}

var firstSquare = Square(length: 3)


println(firstSquare.length)

var secondSquare = Square(length: 10)


println(secondSquare.length)

if firstSquare.length < secondSquare.length {


println("the small square has the length \(firstSquare.length)")
} else {
println("the small square has the length \(secondSquare.length)")
}

Methods

Methods add behaviour to classes and instances.

class Square {
var length: Int = 1

func area() -> Int {


return length * length
}
}

The area() method computes the area of a Square instance when called. To call a method use
the . notation.

var square = Square(5)

println(square.area()) // prints 25
sqare.length = 10

println(square.area()) // prints 100

Class Properties

The usual use of properties are instance properties, like the length of a Square. You can also have
a properties. Below is an example use of class properties. The Tank class has a computed
property named bonusDamage that is used to increase the damage for all tanks when upgrading.
When an upgrade is complete all we need to do is call Tank.upgrade() and all Tank instances
will have more damage.

class Tank {
class var bonusDamage: Double {
return Double(Upgrade.level) * 2.5
}

let baseDamage = 10.0

var damage: Double {


return self.baseDamage + Tank.bonusDamage
}

class func upgrade() {


Upgrade.level += 1
}

struct Upgrade {
static var level = 0
}
}

var tank = Tank()

println(tank.damage)
// 10.0

Tank.upgrade()

println(tank.damage)
// 12.5

Tank.upgrade()

println(tank.damage)
// 15.0
Inheritance

A class can inherit methods, properties, and other characteristics from another class. When one
class inherits from another, the inheriting class is known as a subclass, and the class it inherits
from is known as its superclass. Inheritance is a fundamental behavior that differentiates
classes from other types in Swift.
A simple example of inheritance:

class AClass {
func doSomething() {
println("Hello from AClass")
}
}

class Subclass: AClass {


}

let base_object = AClass()


base_object.doSomething()
//> Hello from AClass

let enhanced_object = Subclass()


enhanced_object.doSomething()
// > Hello from AClass

Overriding

You can override methods in order to provide custom behaviour. To override a method write the
override keyword before the method declaration:

class AClass {
func doSomething() {
println("Hello from AClass")
}
}

class Subclass: AClass {


override func doSomething() {
println("Hello from Subclass")
}
}

let base_object = AClass()


base_object.doSomething()
//> Hello from AClass

let enhanced_object = Subclass()


enhanced_object.doSomething()
//> Hello from Subclass

You can use the super keyword to call any method from the superclass.

...

class Subclass: AClass {


override func doSomething() {
super.doSomething()
println("Hello from Subclass")
}
}

let enhanced_object = Subclass()


enhanced_object.doSomething()
//> Hello from AClass
//> Hello from Subclass
Base class

A class that does not inherit from another class is called a base class, for example:

class User {
var name: String!
var age: Int!

init(name: String, age: Int) {


self.name = name
self.age = age
}
}

The iOS and Mac OS classes usually inherit from NSObject, either directly or indirectly. If you
have a mixt codebase I would encourage you to subclass NSObject when creating a new class:

Swift classes that are subclasses of NSObject:

 are Objective-C classes themselves


 use objc_msgSend() for calls to (most of) their methods
 provide Objective-C runtime metadata for (most of) their method implementations

Swift classes that are not subclasses of NSObject:

 are Objective-C classes, but implement only a handful of methods for NSObject compatibility
 do not use objc_msgSend() for calls to their methods (by default)
 do not provide Objective-C runtime metadata for their method implementations (by default)

Subclassing NSObject in Swift gets you Objective-C runtime flexibility but also Objective-
C performance. Avoiding NSObject can improve performance if you don’t need Objective-
C’s flexibility.

from stackoverflow Swift native base class or NSObject

Protocols

Protocols are declared in a similar way to classes.

protocol MyFirstProtocol {
// I do nothing
}

Protocols describe methods, properties and other requirements that are needed for a specific task.
For example theUITableViewDelegate protocol lists all the methods that can be used to react to
user events and configure a table view.

Note: you can mark a method as optional using the @optional keyword. All of the methods
fromUITableViewDelegate are optional. When you do not use the @optional keyword that
method is required. The swift compiler will throw an error if a class conforms to a protocol and
does not implement the required methods.

A class can conform to a protocol by placing its name after the type’s name separated by a colon,
as part of their definition. Multiple protocols can be listed, and are separated by commas:

class AnotherSwiftClass: MyFirstProtocol, AnotherProtocol {


...
}

If the class inherits from another one, make sure to put the superclass name before the protocol
list.

class AnotherSwiftClass: AClass, MyFirstProtocol, AnotherProtocol {


...
}

Note: Protocols use the same syntax as normal methods, but are not allowed to specify default
values for method parameters.

Delegate Pattern

One of the most overused design pattern in iOS is delegation. A class can delegate a part of it’s
responsibilities to an instance of another class. This design pattern is implemented by defining a
protocol that encapsulates the delegated responsibilities, such that a conforming type (known as a
delegate) is guaranteed to provide the functionality that has been delegated.

Here is an example, the Player class delegates the shooting logic to the weapon:

protocol Targetable {
var life: Int { get set }
func takeDamage(damage: Int)
}

protocol Shootable {
func shoot(target: Targetable)
}

class Pistol: Shootable {


func shoot(target: Targetable) {
target.takeDamage(1)
}
}

class Shotgun: Shootable {


func shoot(target: Targetable) {
target.takeDamage(5)
}
}

class Enemy: Targetable {


var life: Int = 10

func takeDamage(damage: Int) {


life -= damage
println("enemy lost \(damage) hit points")

if life <= 0 {
println("enemy is dead now")
}
}
}

class Player {
var weapon: Shootable!

init(weapon: Shootable) {
self.weapon = weapon
}

func shoot(target: Targetable) {


weapon.shoot(target)
}
}

var terminator = Player(weapon: Pistol())

var enemy = Enemy()

terminator.shoot(enemy)
//> enemy lost 1 hit points
terminator.shoot(enemy)
//> enemy lost 1 hit points
terminator.shoot(enemy)
//> enemy lost 1 hit points
terminator.shoot(enemy)
//> enemy lost 1 hit points
terminator.shoot(enemy)
//> enemy lost 1 hit points

// changing weapon because the pistol is inefficient


terminator.weapon = Shotgun()

terminator.shoot(enemy)
//> enemy lost 5 hit points
//> enemy is dead now
Polymorphism

Polymorphism means “having multiple forms”. Objects of different classes can be used
interchangeably if they have a common superclass.

Here is a simple example in which multiple instances can be used as a GraphicObject.

class GraphicObject {

func draw() {
println("does nothing")
}
}

class SpaceShip: GraphicObject {


}

class EmpireSpaceShip: SpaceShip {


override func draw() {
println("draws an empire space ship")
}
}

class RebellionSpaceShip: SpaceShip {


override func draw() {
println("draws a rebellion space ship")
}
}

class DeathStar: GraphicObject {


override func draw() {
println("draws the Death Star")
}
}

var spaceShips = [EmpireSpaceShip(), RebellionSpaceShip(), DeathStar()]

for spaceShip in spaceShips {


spaceShip.draw()
}

This program will output:

draws an empire space ship


draws a rebellion space ship
draws the Death Star
Singleton Pattern

Sometimes it’s important to have only one instance for a class. For example, in a system there
should be only one window manager (or only a file system, or one motion manager on an
iPhone). To achieve this effect in swift we are going to expose the singleton instance using a
class property.
class Singleton {
struct Static {
static let instance = Singleton()
}

class var sharedInstance: Singleton {


return Static.instance
}
}

Singleton.sharedInstance

or:

import Foundation

class DispatchSingleton {
struct Static {
static var onceToken : dispatch_once_t = 0
static var instance : DispatchSingleton? = nil
}

class var sharedInstance : DispatchSingleton {


dispatch_once(&Static.onceToken) {
Static.instance = DispatchSingleton()
}
return Static.instance!
}
}

DispatchSingleton.sharedInstance
Model View Controller

The best explanation I found was from Apple:

The Model-View-Controller (MVC) design pattern assigns objects in an application one of three
roles: model, view, or controller. The pattern defines not only the roles objects play in the
application, it defines the way objects communicate with each other. Each of the three types of
objects is separated from the others by abstract boundaries and communicates with objects of the
other types across those boundaries. The collection of objects of a certain MVC type in an
application is sometimes referred to as a layer—for example, model layer.

MVC is central to a good design for a Cocoa application. The benefits of adopting this pattern
are numerous. Many objects in these applications tend to be more reusable, and their interfaces
tend to be better defined. Applications having an MVC design are also more easily extensible
than other applications. Moreover, many Cocoa technologies and architectures are based on
MVC and require that your custom objects play one of the MVC roles.

Model Objects
Model objects encapsulate the data specific to an application and define the logic and
computation that manipulate and process that data. For example, a model object might represent
a character in a game or a contact in an address book. A model object can have to-one and to-
many relationships with other model objects, and so sometimes the model layer of an application
effectively is one or more object graphs. Much of the data that is part of the persistent state of the
application (whether that persistent state is stored in files or databases) should reside in the
model objects after the data is loaded into the application. Because model objects represent
knowledge and expertise related to a specific problem domain, they can be reused in similar
problem domains. Ideally, a model object should have no explicit connection to the view objects
that present its data and allow users to edit that data—it should not be concerned with user-
interface and presentation issues.

Communication: User actions in the view layer that create or modify data are communicated
through a controller object and result in the creation or updating of a model object. When a
model object changes (for example, new data is received over a network connection), it notifies a
controller object, which updates the appropriate view objects.

View Objects

A view object is an object in an application that users can see. A view object knows how to draw
itself and can respond to user actions. A major purpose of view objects is to display data from
the application’s model objects and to enable the editing of that data. Despite this, view objects
are typically decoupled from model objects in an MVC application.

Because you typically reuse and reconfigure them, view objects provide consistency between
applications. Both the UIKit and AppKit frameworks provide collections of view classes, and
Interface Builder offers dozens of view objects in its Library.

Communication: View objects learn about changes in model data through the application’s
controller objects and communicate user-initiated changes—for example, text entered in a text
field—through controller objects to an application’s model objects.

Controller Objects

A controller object acts as an intermediary between one or more of an application’s view objects
and one or more of its model objects. Controller objects are thus a conduit through which view
objects learn about changes in model objects and vice versa. Controller objects can also perform
setup and coordinating tasks for an application and manage the life cycles of other objects.

Communication: A controller object interprets user actions made in view objects and
communicates new or changed data to the model layer. When model objects change, a controller
object communicates that new model data to the view objects so that they can display it.
Challenges

 create a Shape base class and derive from it Circle, Square and Rectangle. Shape should
have two methods area() -> Float and perimeter() -> Float that both return 0.
Implement the methods and add the necessary properties on Circle, Square and
Rectangle.
 create the same classes from the first exercise, but this time make Shape a protocol
 create a custom initializer for Circle, Square and Rectangle and create two instance of each
one.
 add the instance created in the exercise above into an array shapes and use polymorphism to
find out the total area and perimeter of the shapes
 solve the exercise above using map and reduce
 add a armor property to the Targetable protocol and reduce the damage taken by the
enemy. Obs: you will need to change the life property type to Float in order to do this.

You might also like