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

JSON mapping and reader monad [DRAFT]

Functional JSON mapping became a hot theme recently. Clear declarative syntax backed by cryptic concepts of monads and applicative functors has exploded many heads. I’d like to talk about a little refinement of our mapping pattern to... Continue →