The new block based KVO on Swift is really great and easy to use. We just need to use observe(_:options:changeHandler:) to register a change event and write code in the changeHandler block(closure) to do the reaction.

But, there is one thing we have to be careful. If we write the code below,

_ = product.observe(\.name, options: [.new, .old]) { (product, change) in
    change.newValue.map{ print("We have new value \($0)")}
}

product.name = "JamCrazy"

You will not get notified by value changed. However, we can try this way. It could be the offical way.

let observation = product.observe(\.name, options: [.new, .old]) { (product, change) in
    change.newValue.map{ print("We have new value \($0)")}
}

product.name = "JamCrazy"

The above code will trigger change event on name property. Do all the setup finish? Not yet.

If we look into the definition in Foundation. We will notice one thing special.

public class NSKeyValueObservation : NSObject {

    ///invalidate() will be called automatically when an NSKeyValueObservation is deinited
    public func invalidate()

}

NSKeyValueObservation is the object that observe(_:options:changeHandler:) returns. From the comment inside NSKeyValueObservation, we can realize that if we don’t retain this object, the changeHandler block is going to invalidate.

So, the correct way would be like this. Use property to retain NSKeyValueObservation or keep it inside a collection object.

let observation = product.observe(\.name, options: [.new, .old]) { (product, change) in
    change.newValue.map{ print("We have new value \($0)")}
}

// Must retain the NSKeyValueObservation object,
// otherwise the invalidate() will be called automatically
observations.append(observation) // observations is a NSKeyValueObservation array