KVO:如何在Swift中的observeValue(forKeyPath:...)中获取旧值/新值?

时间:2014-09-21 12:03:04

标签: swift key-value-observing

我创建了一个.Old | .New选项的观察者。在处理程序方法中,我尝试在值之前获取,但编译器抱怨:' NSString'不能转换为' NSDictionaryIndex:NSObject,AnyObject

override func observeValueForKeyPath(keyPath: String!, ofObject object: AnyObject!, change: [NSObject : AnyObject]!, context: UnsafeMutablePointer<Void>) {

    let approvedOld = change[NSKeyValueChangeOldKey] as Bool
    let approvedNew = change[NSKeyValueChangeNewKey] as Bool

1 个答案:

答案 0 :(得分:10)

iOS 11和Swift&gt; 4.1

iOS 11和Swift 4为KVO带来了重大变化。

  • 这些类应采用@objcMembers注释,以便使KVO或KVO无声地失败。
  • 必须声明要观察的变量dynamic

这是更新的实施,

@objcMembers
class Approval: NSObject {

    dynamic var approved: Bool = false

    let ApprovalObservingContext = UnsafeMutableRawPointer(bitPattern: 1)

    override init() {
        super.init()

        addObserver(self,
                    forKeyPath: #keyPath(approved),
                    options: [.new, .old],
                    context: ApprovalObservingContext)
    }

    override func observeValue(forKeyPath keyPath: String?,
                               of object: Any?,
                               change: [NSKeyValueChangeKey : Any]?,
                               context: UnsafeMutableRawPointer?) {
        guard let observingContext = context,
            observingContext == ApprovalObservingContext else {
                super.observeValue(forKeyPath: keyPath,
                                   of: object,
                                   change: change,
                                   context: context)
                return
        }

        guard let change = change else {
            return
        }

        if let oldValue = change[.oldKey] {
            print("Old value \(oldValue)")
        }

        if let newValue = change[.newKey]  {
            print("New value \(newValue)")
        }

    }

    deinit {
        removeObserver(self, forKeyPath: #keyPath(approved))
    }
}

KVO还有一个新的基于bock的api,就像这样工作,

@objcMembers
class Approval: NSObject {

    dynamic var approved: Bool = false

    var approvalObserver: NSKeyValueObservation!

    override init() {
        super.init()
        approvalObserver = observe(\.approved, options: [.new, .old]) { _, change in
            if let newValue = change.newValue {
                print("New value is \(newValue)")
            }

            if let oldValue = change.oldValue {
                print("Old value is \(oldValue)")
            }
        }

    }
}

基于块的api看起来超级好用且易于使用。此外,KeyValueObservation在deinited时无效,因此不需要删除观察者。

Swift 2.0和iOS&lt; 10

使用Swift 2.0,这是一个使用KVO的类的完整实现,

 class Approval: NSObject {

    dynamic var approved: Bool = false

    let ApprovalObservingContext = UnsafeMutablePointer<Int>(bitPattern: 1)

    override init() {
        super.init()
        addObserver(self, forKeyPath: "approved", options: [.Old, .New], context: ApprovalObservingContext)
    }

    override func observeValueForKeyPath(keyPath: String?,
                                         ofObject object: AnyObject?,
                                                  change: [String : AnyObject]?,
                                                  context: UnsafeMutablePointer<Void>) {

        if let theChange = change as? [String: Bool] {

            if let approvedOld = theChange[NSKeyValueChangeOldKey]  {
                print("Old value \(approvedOld)")
            }

            if let approvedNew = theChange[NSKeyValueChangeNewKey]{
                print("New value \(approvedNew)")

            }

            return
        }
        super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
    }

    deinit {
        removeObserver(self, forKeyPath: "approved")
    }
}

let a  = Approval()
a.approved = true