During this year, I have blogged quite a bit about code architecture in Swift and I’ve realised that I didn’t explain much about which design pattern to use with it. In a serie of coming posts, I will cover different design patterns, starting now with observer.

Observer design pattern is characterised by two elements:

  • A value being observed, notifying in some way all observers of a change.
  • An observer, subscribing to changes of that value

In this post, I’ll get two approaches using protocols and closures to see what’s the most handy.

Observer pattern with protocols

Starting first with the observable, I am going to define what are the condition to fill with a protocol approach. Quite simply, it requires a list of observers and the ability to add, remove one and notify them.

protocol ObservableProtocol : class {
    var observers : [ObserverProtocol] { get set }

    func addObserver(_ observer: ObserverProtocol)
    func removeObserver(_ observer: ObserverProtocol)
    func notifyObservers(_ observers: [ObserverProtocol])
}

On the other side, we need an observer capable of receiving a callback when the value changed. I’m adding an identifier to it for some duplicate safety later.

protocol ObserverProtocol {

    var id : Int { get set }
    func onValueChanged(_ value: Any?)
}

A key ingredient to avoid issues later is to bound the _ ObservableProtocol_ to a class. In case you implement it to a struct, and because structs are value typed, you might not have always the right values you want to work with.

Here is what my observable class looks, using generic to make it reusable regardless the type of values I want to work with.

class Observable<T> : ObservableProtocol {

    var value : T {
        didSet {
            self.notifyObservers(self.observers)
        }
    }

    internal var observers : [ObserverProtocol] = []

    init(value: T) {
        self.value = value
    }

    func addObserver(_ observer: ObserverProtocol) {
        guard self.observers.contains(where: { $0.id == observer.id }) == false else {
            return
        }
        self.observers.append(observer)
    }

    func removeObserver(_ observer: ObserverProtocol) {
        guard let index = self.observers.firstIndex(where: { $0.id == observer.id }) else {
            return
        }
        self.observers.remove(at: index)

    }

    func notifyObservers(_ observers: [ObserverProtocol]) {
        observers.forEach({ $0.onValueChanged(value)})
    }

    deinit {
        observers.removeAll()
    }
}

Finishing with a small test on Playground.

struct Children {
    var age : Observable<Int>

    init(age: Int) {
        self.age = Observable(value: age)
    }
}

struct Parent : ObserverProtocol {

    var id = 123
    func onValueChanged(_ value: Any?) {
        // give birthday present
        print("new age \(value)")
    }
}

let bobby = Children(age: 10)
let mommy = Parent()
bobby.age.addObserver(mommy)

bobby.age.value = 11
// print "new age Optional(11)"

Great, it’s working as expected with this simple example.

However, you might work with classes and add relations in between that can cause you trouble and leak memory. For instance, a simple UITableViewController observing an array that it owns, you’ll get a retain cycle.

At the same time, “onValueChanged” doesn’t help you much if you have multiple values observed to know which one to handle. Let’s see if we can get a swift friendly alternative.


Observer pattern with closures

Instead of using a specific function for every observer, like a delegate would do, let’s see if a closure as parameter can tidy the observer.

class Observable<T> {

    typealias CompletionHandler = ((T) -> Void)

    var value : T {
        didSet {
            self.notifyObservers(self.observers)
        }
    }

    var observers : [Int : CompletionHandler] = [:]

    init(value: T) {
        self.value = value
    }

    func addObserver(_ observer: ObserverProtocol, completion: @escaping CompletionHandler) {
        self.observers[observer.id] = completion
    }

    func removeObserver(_ observer: ObserverProtocol) {
        self.observers.removeValue(forKey: observer.id)        
    }

    func notifyObservers(_ observers: [Int : CompletionHandler]) {
        observers.forEach({ $0.value(value) })
    }

    deinit {
        observers.removeAll()
    }
}

The idea is to keep a collection of closures to execute instead of observers. It helps to reduce risk of strong references, I chose to keep it into dictionary in case we want to remove it by their identifiers.

struct Parent : ObserverProtocol {
    var id = 123
}

let bobby = Children(age: 10)
let mommy = Parent()
bobby.age.addObserver(mommy) { newAge in
    print("Let's throw a birthday party")
}

bobby.isGraduationDay.addObserver(mommy) { isGraduationDay in
    print("Let's throw a graduation party")
}

bobby.age.value = 11
// print **Let's throw a birthday party**
bobby.isGraduationDay.value = true
// print **Let's a throw graduation party**

In conclusion, we’ve seen how to implement a simple observer in Swift, using protocols and closures to notify changes of the value being observed.

Observer design pattern is very handy when you are facing a one-to-many relationship between classes and you want to broadcast changes all at once. However, like any design patterns, it comes with some limitations and it’s up to the developers to balance it and find the best solution, keeping a clean code and avoiding memory leaks.

Thanks for reading