Key-Value Observing (KVO) is considered as one of the most powerful features of Cocoa. However, at the same time, it is also notorious for the hard-to-use APIs. Different from property observing discussed before, the target of KVO is not for supplying a hook on properties of current type/instance, but giving a chance to other instances to listen to the change of a specified property (or keypath strictly speaking). Other instances act as subscribers. Whenever the listened property changed, the subscribers will get noticed.

KVO is really a cool feature, especially we want to implement a loose structure. It makes our code flexible: you can listen to the value of model and update UI (yes, it is a binding), and do other similar things with KVO.

We can use KVO in Swift as well, but restricted in subclass of NSObject. It is reasonable since KVO is a technology based on Key-Value Coding (KVC) and dynamic dispatching. All of them are concepts of Objective-C runtime. Except for that, we also need to mark the property we want to observe to dynamic, or the dynamic dispatch will be forbidden.

To implement KVO for an NSObject subclass in Swift:

class MyClass: NSObject {
    dynamic var date = NSDate()

private var myContext = 0

class ViewController: UIViewController {

    var myObject: MyClass!

    override func viewDidLoad() {

        myObject = MyClass()
        print("MyClass init. Date: \(")
                             forKeyPath: "date", 
                                options: .New, 
                                context: &myContext)

        delay(3) {
   = NSDate()

    override func observeValueForKeyPath(keyPath: String, 
                                 ofObject object: AnyObject, 
                                          change: [NSObject: AnyObject], 
                                         context: UnsafeMutablePointer<Void>)
        if context == &myContext {
            print("Date is changed. \(change[NSKeyValueChangeNewKey])")

In the code above, we are using a method called delay, which is not a method of Swift standard library. You can get more about it from the tip of GCD and delayed invoking in this book.

Here it is sufficient to understand that the date property of myObject will be updated after 3 seconds.

As we marked date of MyClass with dynamic, it will follow the traditional Objective-C way to notify its observers when the value changes. Put this code into a project and run, the output should be:

MyClass init. Date: 2014-08-23 16:37:20 +0000
Date is changed. Optional(2014-08-23 16:37:23 +0000)

Remember, the new value is taken from a dictionary. Although we can make sure there is a value for this specified key (NSKeyValueChangeNewKey), it is still a good behavior to check nil or do an optional binding before use it.

There are two concerns when using KVO in Swift.

First, there are more dependency to use KVO in Swift. In the age of Objective-C, we can listen to almost all properties without limitation since they follow KVC approach. However, unless the developers intend to do, it is just not possible for a property marked as dynamic. We can add it before the property if only we have write permission of the source. However, more often we only want to use a framework. In that situation, we may need to add a subclass as a layer and use it to add KVO support to the original class:

class MyClass: NSObject {
    var date = NSDate()

class MyChildClass: MyClass {
    dynamic override var date: NSDate {
        get { return }
        set { = newValue }

No logic modification is needed. So we can simply call super version of the getter and setter.

Another concern is how about pure Swift types not inheriting NSObject. Type and property of Swift is not implemented with KVC, so there is no way to apply KVO for it. There is no similar mechanism in Swift currently. With property observer, we can implement an alternative ourselves. With generic and closure, it is not so hard to make things elegant and useful. Observable-Swift already did some work on it. It could be a great project if you want to use KVO in your Swift project.