Write yourself KVO in Swift

KVO is a major part of Objective-C dynamic nature. Having virtually every property or ivar observable by its key path opens doors to simple bindings or advanced technologies like ReactiveCocoa.

But what about Swift? It’s static nature shuts the possibility to observe properties of any class not willing to do so (by means of willSet and didSet). Not nice.

If we are going to observe something static, we need at least two things: a list of names of observable fields and a way to get their values by that name. Reminds of anything? Of course, that’s what Dictionary does.

Let’s define a goal. Assume we have a Swift dictionary of Any, and we want to add some observer block bound to particular key to be called when the value of that key gets changed. As a first step we will ignore the complexity of key-path navigation and start with a single key observation.

What do we need? First, a class to wrap our Dictionary and a list of observers:

class ObservableDictionary {
    typealias Observer = Any -> ()

    private var dict = [String: Any]()
    private var observers = [String: [Observer]]()
}

Then a method for adding observer:

extension ObservableDictionary {
    func addObserver(key: String, observer: Observer) {
        var list = observers[key] ?? []
        list.append(observer)
        observers[key] = list
    }
}

And finally a setter that will trigger all observers registered for given key:

extension ObservableDictionary {
    subscript(key: String) -> Any {
        get {
            return dict[key]
        }
        set(value) {
            dict[key] = value
            if let list = observers[key] {
                map(list) { $0(value) }
            }
        }
    }
}

And that’s it! Let’s test it:

let dict = ObservableDictionary()
dict.addObserver("name") {
    newValue in
    println("New name: \(newValue))")
    newValue
}
dict["age"] = 30
dict["name"] = "Someone"

Simple, huh? Yet the big part is yet to be done - making this stuff work with real key paths. That will be a subject for my next post.

You can download Swift playground for this post

 
15
Kudos
 
15
Kudos

Now read this

Facebook iOS Infrastructure talk

I’d like to share this brilliant talk from Facebook regarding their experience in building Facebook app. One of the most important problems for them was to tame model layer performance. As a part of their migration from HTML to native... Continue →