关键值观察(KVO)在Swift中可用吗?

时间:2021-01-11 16:55:56

If so, are there any key differences that weren't otherwise present when using key-value observation in Objective-C?

如果是这样,那么在Objective-C中使用键值观察时,是否存在其他不存在的关键差异?

10 个解决方案

#1


96  

Yes and no. KVO works on NSObject subclasses much as it always has. It does not work for classes that don't subclass NSObject. Swift does not (currently at least) have its own native observation system.

是的,没有。KVO在NSObject的子类上工作,一如既往。它不适用于没有NSObject子类的类。斯威夫特(目前至少)没有自己的本土观察系统。

(See comments for how to expose other properties as ObjC so KVO works on them)

(请参阅如何将其他属性公开为ObjC,以便KVO处理)

See the Apple Documentation for a full example.

有关完整的示例,请参阅Apple文档。

#2


131  

You can use KVO in Swift, but only for dynamic properties of NSObject subclass. Consider that you wanted to observe the bar property of a Foo class. In Swift 4, specify bar as dynamic property in your NSObject subclass:

您可以在Swift中使用KVO,但仅用于NSObject子类的动态属性。考虑您想要观察Foo类的bar属性。在Swift 4中,将bar指定为NSObject子类中的动态属性:

class Foo: NSObject {
    @objc dynamic var bar = 0
}

You can then register to observe changes to the bar property. In Swift 4 and Swift 3.2, this has been greatly simplified:

然后,您可以注册观察对bar属性的更改。在Swift 4和Swift 3.2中,这被大大简化了:

class MyObject {
    private var token: NSKeyValueObservation

    var objectToObserve = Foo()

    init() {
        token = objectToObserve.observe(\.bar) { [weak self] object, change in  // the `[weak self]` is to avoid strong reference cycle; obviously, if you don't reference `self` in the closure, then `[weak self]` is not needed
            print("bar property is now \(object.bar)")
        }
    }
}

Note, in Swift 4, we now have strong typing of keypaths using the backslash character (the \.bar is the keypath for the bar property of the object being observed). Also, because it's using the completion closure pattern, we don't have to manually remove observers (when the token falls out of scope, the observer is removed for us) nor do we have to worry about calling the super implementation if the key doesn't match. The closure is called only when this particular observer is invoked. For more information, see WWDC 2017 video, What's New in Foundation.

注意,在Swift 4中,我们现在使用反斜杠字符(\bar是被观察对象的bar属性的关键路径。另外,因为它使用的是完成闭包模式,所以我们不需要手动删除观察者(当令牌超出范围时,观察者就会被删除),也不需要担心在键不匹配的情况下调用super实现。只有在调用这个特定的观察者时才调用闭包。有关更多信息,请参见WWDC 2017视频。

In Swift 3, to observe this, it's a bit more complicated, but very similar to what one does in Objective-C. Namely, you would implement observeValue(forKeyPath keyPath:, of object:, change:, context:) which (a) makes sure we're dealing with our context (and not something that our super instance had registered to observe); and then (b) either handle it or pass it on to the super implementation, as necessary. And make sure to remove yourself as an observer when appropriate. For example, you might remove the observer when it is deallocated:

在Swift 3中,要观察到这一点,它有点复杂,但与Objective-C中的操作非常相似。也就是说,您将实现observeValue(forKeyPath keyPath keyPath:, of object:, change:, context:),其中(a)确保我们正在处理我们的上下文(而不是我们的超实例注册要观察的内容);然后(b)根据需要处理它或将它传递给超级实现。确保在适当的时候把自己从观察者的位置移开。例如,当观察者被释放时,您可以删除它:

In Swift 3:

在斯威夫特3:

class MyObject: NSObject {
    private var observerContext = 0

    var objectToObserve = Foo()

    override init() {
        super.init()

        objectToObserve.addObserver(self, forKeyPath: #keyPath(Foo.bar), options: [.new, .old], context: &observerContext)
    }

    deinit {
        objectToObserve.removeObserver(self, forKeyPath: #keyPath(Foo.bar), context: &observerContext)
    }

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

        // do something upon notification of the observed object

        print("\(keyPath): \(change?[.newKey])")
    }

}

Note, you can only observe properties that can be represented in Objective-C. Thus, you cannot observe generics, Swift struct types, Swift enum types, etc.

注意,您只能观察可以在Objective-C中表示的属性。因此,您不能观察泛型、快速结构类型、快速枚举类型等。

For a discussion of the Swift 2 implementation, see my original answer, below.

有关Swift 2实现的讨论,请参见下面我的原始答案。


Using the dynamic keyword to achieve KVO with NSObject subclasses is described in the Key-Value Observing section of the Adopting Cocoa Design Conventions chapter of the Using Swift with Cocoa and Objective-C guide:

使用dynamic关键字来实现带有NSObject子类的KVO在采用Cocoa设计惯例章节的关键值观察部分描述了与Cocoa一起使用Swift和Objective-C指南:

Key-value observing is a mechanism that allows objects to be notified of changes to specified properties of other objects. You can use key-value observing with a Swift class, as long as the class inherits from the NSObject class. You can use these three steps to implement key-value observing in Swift.

键值观察是一种机制,它允许对象被通知对其他对象的指定属性的更改。只要类继承自NSObject类,就可以使用Swift类的键值观察。您可以使用这三个步骤在Swift中实现键值观察。

  1. Add the dynamic modifier to any property you want to observe. For more information on dynamic, see Requiring Dynamic Dispatch.

    将动态修改器添加到您想要观察的任何属性。有关动态的更多信息,请参见需要动态调度。

    class MyObjectToObserve: NSObject {
        dynamic var myDate = NSDate()
        func updateDate() {
            myDate = NSDate()
        }
    }
    
  2. Create a global context variable.

    创建一个全局上下文变量。

    private var myContext = 0
    
  3. Add an observer for the key-path, and override the observeValueForKeyPath:ofObject:change:context: method, and remove the observer in deinit.

    为键路径添加一个观察者,并覆盖observeValueForKeyPath:ofObject:change:context: method,并删除deinit中的观察者。

    class MyObserver: NSObject {
        var objectToObserve = MyObjectToObserve()
        override init() {
            super.init()
            objectToObserve.addObserver(self, forKeyPath: "myDate", options: .New, context: &myContext)
        }
    
        override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
            if context == &myContext {
                if let newValue = change?[NSKeyValueChangeNewKey] {
                    print("Date changed: \(newValue)")
                }
            } else {
                super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
            }
        }
    
        deinit {
            objectToObserve.removeObserver(self, forKeyPath: "myDate", context: &myContext)
        }
    }
    

[Note, this KVO discussion has subsequently been removed from the Using Swift with Cocoa and Objective-C guide, which has been adapted for Swift 3, but it still works as outlined at the top of this answer.]

[注意,这个KVO的讨论后来被从使用Swift with Cocoa和Objective-C guide中删除了,后者已经被改编为Swift 3,但是它仍然可以按照上面的答案工作。]


It's worth noting that Swift has its own native property observer system, but that's for a class specifying its own code that will be performed upon observation of its own properties. KVO, on the other hand, is designed to register to observe changes to some dynamic property of some other class.

值得注意的是,Swift有自己的本地属性观察者系统,但这是针对一个类的,该类指定自己的代码,该代码将在观察自身属性时执行。另一方面,KVO被设计用来观察一些其他类的动态特性的变化。

#3


90  

Both yes and no:

两个“是”和“不是”:

  • Yes, you can use the same old KVO APIs in Swift to observe Objective-C objects.
    You can also observe dynamic properties of Swift objects inheriting from NSObject.
    But... No it's not strongly typed as you could expect Swift native observation system to be.
    Using Swift with Cocoa and Objective-C | Key Value Observing

    是的,您可以在Swift中使用相同的KVO api来观察Objective-C对象。您还可以观察从NSObject继承的Swift对象的动态属性。但是…不,它不是强类型的,你可以预期快速本地观测系统。使用Swift与Cocoa和Objective-C |键值观察

  • No, currently there is no builtin value observation system for arbitrary Swift objects.

    不,目前对于任意的Swift对象没有构建值观察系统。

  • Yes, there are builtin Property Observers, which are strongly typed.
    But... No they are not KVO, since they allow only for observing of objects own properties, don't support nested observations ("key paths"), and you have to explicitly implement them.
    The Swift Programming Language | Property Observers

    是的,有构建属性观察者,它们是强类型的。但是…不,它们不是KVO,因为它们只允许观察对象本身的属性,不支持嵌套的观察(“关键路径”),您必须显式地实现它们。Swift编程语言|属性观察者

  • Yes, you can implement explicit value observing, which will be strongly typed, and allow for adding multiple handlers from other objects, and even support nesting / "key paths".
    But... No it will not be KVO since it will only work for properties which you implement as observable.
    You can find a library for implementing such value observing here:
    Observable-Swift - KVO for Swift - Value Observing and Events

    是的,您可以实现显式值观察,它将是强类型的,并且允许从其他对象添加多个处理程序,甚至支持嵌套/“关键路径”。但是…不,它不会是KVO,因为它只适用于可观察的属性。您可以在这里找到一个实现这种值观察的库:Swift -Swift - KVO用于Swift - value观察和事件

#4


10  

An example might help a little here. If I have an instance model of class Model with attributes name and state I can observe those attributes with:

这里有一个例子可能会有所帮助。如果我有一个具有属性名和状态的类模型的实例,我可以用:

let options = NSKeyValueObservingOptions([.New, .Old, .Initial, .Prior])

model.addObserver(self, forKeyPath: "name", options: options, context: nil)
model.addObserver(self, forKeyPath: "state", options: options, context: nil)

Changes to these properties will trigger a call to:

对这些属性的更改将触发以下调用:

override func observeValueForKeyPath(keyPath: String!,
    ofObject object: AnyObject!,
    change: NSDictionary!,
    context: CMutableVoidPointer) {

        println("CHANGE OBSERVED: \(change)")
}

#5


8  

Yes.

是的。

KVO requires dynamic dispatch, so you simply need to add the dynamic modifier to a method, property, subscript, or initializer:

KVO需要动态调度,因此只需将动态修饰符添加到方法、属性、下标或初始化器:

dynamic var foo = 0

动态var foo = 0。

The dynamic modifier ensures that references to the declaration will be dynamically dispatched and accessed through objc_msgSend.

动态修饰符确保对声明的引用将通过objc_msgSend动态发送和访问。

#6


5  

Currently Swift does not support any built in mechanism for observing property changes of objects other than 'self', so no, it does not support KVO.

目前Swift不支持任何用于观察除“自我”之外的对象属性变化的内置机制,所以不支持KVO。

However, KVO is such a fundamental part of Objective-C and Cocoa that it seems quite likely that it will be added in the future. The current documentation seems to imply this:

然而,KVO是Objective-C和Cocoa的基本组成部分,它很有可能在未来被添加进来。目前的文件似乎表明:

Key-Value Observing

键-值观察

Information forthcoming.

即将到来的信息。

Using Swift with Cocoa and Objective-C

使用Swift与Cocoa和Objective-C

#7


5  

In addition to Rob's answer. That class must inherit from NSObject, and we have 3 ways to trigger property change

除了罗布的回答。这个类必须继承自NSObject,我们有三种方法来触发属性更改

Use setValue(value: AnyObject?, forKey key: String) from NSKeyValueCoding

使用setValue(价值:AnyObject ?,forKey key: String) from NSKeyValueCoding。

class MyObjectToObserve: NSObject {
    var myDate = NSDate()
    func updateDate() {
        setValue(NSDate(), forKey: "myDate")
    }
}

Use willChangeValueForKey and didChangeValueForKey from NSKeyValueObserving

使用willChangeValueForKey和didChangeValueForKey从nskeyvalueobservation

class MyObjectToObserve: NSObject {
    var myDate = NSDate()
    func updateDate() {
        willChangeValueForKey("myDate")
        myDate = NSDate()
        didChangeValueForKey("myDate")
    }
}

Use dynamic. See Swift Type Compatibility

使用动态。看到斯威夫特类型兼容性

You can also use the dynamic modifier to require that access to members be dynamically dispatched through the Objective-C runtime if you’re using APIs like key–value observing that dynamically replace the implementation of a method.

您还可以使用动态修饰符来要求通过Objective-C运行时动态分配对成员的访问,如果您使用的是诸如键值观察之类的api,这些api可以动态地替换方法的实现。

class MyObjectToObserve: NSObject {
    dynamic var myDate = NSDate()
    func updateDate() {
        myDate = NSDate()
    }
}

And property getter and setter is called when used. You can verify when working with KVO. This is an example of computed property

使用时将调用属性getter和setter。您可以在使用KVO时进行验证。这是计算属性的一个例子

class MyObjectToObserve: NSObject {
    var backing: NSDate = NSDate()
    dynamic var myDate: NSDate {
        set {
            print("setter is called")
            backing = newValue
        }
        get {
            print("getter is called")
            return backing
        }
    }
}

#8


4  

One important thing to mention is that after updating your Xcode to 7 beta you might be getting the following message: "Method does not override any method from its superclass". That's because of the arguments' optionality. Make sure that your observation handler looks exactly as follows:

需要注意的是,在将Xcode更新为7 beta之后,您可能会得到以下消息:“方法不会覆盖其超类中的任何方法”。这是因为参数的可选性。确保您的观察处理程序如下所示:

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

#9


2  

This may be prove helpful to few people -

这可能对少数人有帮助

// MARK: - KVO

var observedPaths: [String] = []

func observeKVO(keyPath: String) {
    observedPaths.append(keyPath)
    addObserver(self, forKeyPath: keyPath, options: [.old, .new], context: nil)
}

func unObserveKVO(keyPath: String) {
    if let index = observedPaths.index(of: keyPath) {
        observedPaths.remove(at: index)
    }
    removeObserver(self, forKeyPath: keyPath)
}

func unObserveAllKVO() {
    for keyPath in observedPaths {
        removeObserver(self, forKeyPath: keyPath)
    }
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if let keyPath = keyPath {
        switch keyPath {
        case #keyPath(camera.iso):
            slider.value = camera.iso
        default:
            break
        }
    }
}

I had used KVO in this way in Swift 3. You can use this code with few changes.

我在Swift 3中使用了KVO。您可以使用此代码,只需做一些更改。

#10


1  

Another example for anyone who runs into a problem with types such as Int? and CGFloat?. You simply set you class as a subclass of NSObject and declare your variables as follows e.g:

对于任何遇到类型(如Int)问题的人来说,这是另一个例子。和CGFloat ?。您只需将类设置为NSObject的子类并声明变量如下:

class Theme : NSObject{

   dynamic var min_images : Int = 0
   dynamic var moreTextSize : CGFloat = 0.0

   func myMethod(){
       self.setValue(value, forKey: "\(min_images)")
   }

}

#1


96  

Yes and no. KVO works on NSObject subclasses much as it always has. It does not work for classes that don't subclass NSObject. Swift does not (currently at least) have its own native observation system.

是的,没有。KVO在NSObject的子类上工作,一如既往。它不适用于没有NSObject子类的类。斯威夫特(目前至少)没有自己的本土观察系统。

(See comments for how to expose other properties as ObjC so KVO works on them)

(请参阅如何将其他属性公开为ObjC,以便KVO处理)

See the Apple Documentation for a full example.

有关完整的示例,请参阅Apple文档。

#2


131  

You can use KVO in Swift, but only for dynamic properties of NSObject subclass. Consider that you wanted to observe the bar property of a Foo class. In Swift 4, specify bar as dynamic property in your NSObject subclass:

您可以在Swift中使用KVO,但仅用于NSObject子类的动态属性。考虑您想要观察Foo类的bar属性。在Swift 4中,将bar指定为NSObject子类中的动态属性:

class Foo: NSObject {
    @objc dynamic var bar = 0
}

You can then register to observe changes to the bar property. In Swift 4 and Swift 3.2, this has been greatly simplified:

然后,您可以注册观察对bar属性的更改。在Swift 4和Swift 3.2中,这被大大简化了:

class MyObject {
    private var token: NSKeyValueObservation

    var objectToObserve = Foo()

    init() {
        token = objectToObserve.observe(\.bar) { [weak self] object, change in  // the `[weak self]` is to avoid strong reference cycle; obviously, if you don't reference `self` in the closure, then `[weak self]` is not needed
            print("bar property is now \(object.bar)")
        }
    }
}

Note, in Swift 4, we now have strong typing of keypaths using the backslash character (the \.bar is the keypath for the bar property of the object being observed). Also, because it's using the completion closure pattern, we don't have to manually remove observers (when the token falls out of scope, the observer is removed for us) nor do we have to worry about calling the super implementation if the key doesn't match. The closure is called only when this particular observer is invoked. For more information, see WWDC 2017 video, What's New in Foundation.

注意,在Swift 4中,我们现在使用反斜杠字符(\bar是被观察对象的bar属性的关键路径。另外,因为它使用的是完成闭包模式,所以我们不需要手动删除观察者(当令牌超出范围时,观察者就会被删除),也不需要担心在键不匹配的情况下调用super实现。只有在调用这个特定的观察者时才调用闭包。有关更多信息,请参见WWDC 2017视频。

In Swift 3, to observe this, it's a bit more complicated, but very similar to what one does in Objective-C. Namely, you would implement observeValue(forKeyPath keyPath:, of object:, change:, context:) which (a) makes sure we're dealing with our context (and not something that our super instance had registered to observe); and then (b) either handle it or pass it on to the super implementation, as necessary. And make sure to remove yourself as an observer when appropriate. For example, you might remove the observer when it is deallocated:

在Swift 3中,要观察到这一点,它有点复杂,但与Objective-C中的操作非常相似。也就是说,您将实现observeValue(forKeyPath keyPath keyPath:, of object:, change:, context:),其中(a)确保我们正在处理我们的上下文(而不是我们的超实例注册要观察的内容);然后(b)根据需要处理它或将它传递给超级实现。确保在适当的时候把自己从观察者的位置移开。例如,当观察者被释放时,您可以删除它:

In Swift 3:

在斯威夫特3:

class MyObject: NSObject {
    private var observerContext = 0

    var objectToObserve = Foo()

    override init() {
        super.init()

        objectToObserve.addObserver(self, forKeyPath: #keyPath(Foo.bar), options: [.new, .old], context: &observerContext)
    }

    deinit {
        objectToObserve.removeObserver(self, forKeyPath: #keyPath(Foo.bar), context: &observerContext)
    }

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

        // do something upon notification of the observed object

        print("\(keyPath): \(change?[.newKey])")
    }

}

Note, you can only observe properties that can be represented in Objective-C. Thus, you cannot observe generics, Swift struct types, Swift enum types, etc.

注意,您只能观察可以在Objective-C中表示的属性。因此,您不能观察泛型、快速结构类型、快速枚举类型等。

For a discussion of the Swift 2 implementation, see my original answer, below.

有关Swift 2实现的讨论,请参见下面我的原始答案。


Using the dynamic keyword to achieve KVO with NSObject subclasses is described in the Key-Value Observing section of the Adopting Cocoa Design Conventions chapter of the Using Swift with Cocoa and Objective-C guide:

使用dynamic关键字来实现带有NSObject子类的KVO在采用Cocoa设计惯例章节的关键值观察部分描述了与Cocoa一起使用Swift和Objective-C指南:

Key-value observing is a mechanism that allows objects to be notified of changes to specified properties of other objects. You can use key-value observing with a Swift class, as long as the class inherits from the NSObject class. You can use these three steps to implement key-value observing in Swift.

键值观察是一种机制,它允许对象被通知对其他对象的指定属性的更改。只要类继承自NSObject类,就可以使用Swift类的键值观察。您可以使用这三个步骤在Swift中实现键值观察。

  1. Add the dynamic modifier to any property you want to observe. For more information on dynamic, see Requiring Dynamic Dispatch.

    将动态修改器添加到您想要观察的任何属性。有关动态的更多信息,请参见需要动态调度。

    class MyObjectToObserve: NSObject {
        dynamic var myDate = NSDate()
        func updateDate() {
            myDate = NSDate()
        }
    }
    
  2. Create a global context variable.

    创建一个全局上下文变量。

    private var myContext = 0
    
  3. Add an observer for the key-path, and override the observeValueForKeyPath:ofObject:change:context: method, and remove the observer in deinit.

    为键路径添加一个观察者,并覆盖observeValueForKeyPath:ofObject:change:context: method,并删除deinit中的观察者。

    class MyObserver: NSObject {
        var objectToObserve = MyObjectToObserve()
        override init() {
            super.init()
            objectToObserve.addObserver(self, forKeyPath: "myDate", options: .New, context: &myContext)
        }
    
        override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
            if context == &myContext {
                if let newValue = change?[NSKeyValueChangeNewKey] {
                    print("Date changed: \(newValue)")
                }
            } else {
                super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
            }
        }
    
        deinit {
            objectToObserve.removeObserver(self, forKeyPath: "myDate", context: &myContext)
        }
    }
    

[Note, this KVO discussion has subsequently been removed from the Using Swift with Cocoa and Objective-C guide, which has been adapted for Swift 3, but it still works as outlined at the top of this answer.]

[注意,这个KVO的讨论后来被从使用Swift with Cocoa和Objective-C guide中删除了,后者已经被改编为Swift 3,但是它仍然可以按照上面的答案工作。]


It's worth noting that Swift has its own native property observer system, but that's for a class specifying its own code that will be performed upon observation of its own properties. KVO, on the other hand, is designed to register to observe changes to some dynamic property of some other class.

值得注意的是,Swift有自己的本地属性观察者系统,但这是针对一个类的,该类指定自己的代码,该代码将在观察自身属性时执行。另一方面,KVO被设计用来观察一些其他类的动态特性的变化。

#3


90  

Both yes and no:

两个“是”和“不是”:

  • Yes, you can use the same old KVO APIs in Swift to observe Objective-C objects.
    You can also observe dynamic properties of Swift objects inheriting from NSObject.
    But... No it's not strongly typed as you could expect Swift native observation system to be.
    Using Swift with Cocoa and Objective-C | Key Value Observing

    是的,您可以在Swift中使用相同的KVO api来观察Objective-C对象。您还可以观察从NSObject继承的Swift对象的动态属性。但是…不,它不是强类型的,你可以预期快速本地观测系统。使用Swift与Cocoa和Objective-C |键值观察

  • No, currently there is no builtin value observation system for arbitrary Swift objects.

    不,目前对于任意的Swift对象没有构建值观察系统。

  • Yes, there are builtin Property Observers, which are strongly typed.
    But... No they are not KVO, since they allow only for observing of objects own properties, don't support nested observations ("key paths"), and you have to explicitly implement them.
    The Swift Programming Language | Property Observers

    是的,有构建属性观察者,它们是强类型的。但是…不,它们不是KVO,因为它们只允许观察对象本身的属性,不支持嵌套的观察(“关键路径”),您必须显式地实现它们。Swift编程语言|属性观察者

  • Yes, you can implement explicit value observing, which will be strongly typed, and allow for adding multiple handlers from other objects, and even support nesting / "key paths".
    But... No it will not be KVO since it will only work for properties which you implement as observable.
    You can find a library for implementing such value observing here:
    Observable-Swift - KVO for Swift - Value Observing and Events

    是的,您可以实现显式值观察,它将是强类型的,并且允许从其他对象添加多个处理程序,甚至支持嵌套/“关键路径”。但是…不,它不会是KVO,因为它只适用于可观察的属性。您可以在这里找到一个实现这种值观察的库:Swift -Swift - KVO用于Swift - value观察和事件

#4


10  

An example might help a little here. If I have an instance model of class Model with attributes name and state I can observe those attributes with:

这里有一个例子可能会有所帮助。如果我有一个具有属性名和状态的类模型的实例,我可以用:

let options = NSKeyValueObservingOptions([.New, .Old, .Initial, .Prior])

model.addObserver(self, forKeyPath: "name", options: options, context: nil)
model.addObserver(self, forKeyPath: "state", options: options, context: nil)

Changes to these properties will trigger a call to:

对这些属性的更改将触发以下调用:

override func observeValueForKeyPath(keyPath: String!,
    ofObject object: AnyObject!,
    change: NSDictionary!,
    context: CMutableVoidPointer) {

        println("CHANGE OBSERVED: \(change)")
}

#5


8  

Yes.

是的。

KVO requires dynamic dispatch, so you simply need to add the dynamic modifier to a method, property, subscript, or initializer:

KVO需要动态调度,因此只需将动态修饰符添加到方法、属性、下标或初始化器:

dynamic var foo = 0

动态var foo = 0。

The dynamic modifier ensures that references to the declaration will be dynamically dispatched and accessed through objc_msgSend.

动态修饰符确保对声明的引用将通过objc_msgSend动态发送和访问。

#6


5  

Currently Swift does not support any built in mechanism for observing property changes of objects other than 'self', so no, it does not support KVO.

目前Swift不支持任何用于观察除“自我”之外的对象属性变化的内置机制,所以不支持KVO。

However, KVO is such a fundamental part of Objective-C and Cocoa that it seems quite likely that it will be added in the future. The current documentation seems to imply this:

然而,KVO是Objective-C和Cocoa的基本组成部分,它很有可能在未来被添加进来。目前的文件似乎表明:

Key-Value Observing

键-值观察

Information forthcoming.

即将到来的信息。

Using Swift with Cocoa and Objective-C

使用Swift与Cocoa和Objective-C

#7


5  

In addition to Rob's answer. That class must inherit from NSObject, and we have 3 ways to trigger property change

除了罗布的回答。这个类必须继承自NSObject,我们有三种方法来触发属性更改

Use setValue(value: AnyObject?, forKey key: String) from NSKeyValueCoding

使用setValue(价值:AnyObject ?,forKey key: String) from NSKeyValueCoding。

class MyObjectToObserve: NSObject {
    var myDate = NSDate()
    func updateDate() {
        setValue(NSDate(), forKey: "myDate")
    }
}

Use willChangeValueForKey and didChangeValueForKey from NSKeyValueObserving

使用willChangeValueForKey和didChangeValueForKey从nskeyvalueobservation

class MyObjectToObserve: NSObject {
    var myDate = NSDate()
    func updateDate() {
        willChangeValueForKey("myDate")
        myDate = NSDate()
        didChangeValueForKey("myDate")
    }
}

Use dynamic. See Swift Type Compatibility

使用动态。看到斯威夫特类型兼容性

You can also use the dynamic modifier to require that access to members be dynamically dispatched through the Objective-C runtime if you’re using APIs like key–value observing that dynamically replace the implementation of a method.

您还可以使用动态修饰符来要求通过Objective-C运行时动态分配对成员的访问,如果您使用的是诸如键值观察之类的api,这些api可以动态地替换方法的实现。

class MyObjectToObserve: NSObject {
    dynamic var myDate = NSDate()
    func updateDate() {
        myDate = NSDate()
    }
}

And property getter and setter is called when used. You can verify when working with KVO. This is an example of computed property

使用时将调用属性getter和setter。您可以在使用KVO时进行验证。这是计算属性的一个例子

class MyObjectToObserve: NSObject {
    var backing: NSDate = NSDate()
    dynamic var myDate: NSDate {
        set {
            print("setter is called")
            backing = newValue
        }
        get {
            print("getter is called")
            return backing
        }
    }
}

#8


4  

One important thing to mention is that after updating your Xcode to 7 beta you might be getting the following message: "Method does not override any method from its superclass". That's because of the arguments' optionality. Make sure that your observation handler looks exactly as follows:

需要注意的是,在将Xcode更新为7 beta之后,您可能会得到以下消息:“方法不会覆盖其超类中的任何方法”。这是因为参数的可选性。确保您的观察处理程序如下所示:

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

#9


2  

This may be prove helpful to few people -

这可能对少数人有帮助

// MARK: - KVO

var observedPaths: [String] = []

func observeKVO(keyPath: String) {
    observedPaths.append(keyPath)
    addObserver(self, forKeyPath: keyPath, options: [.old, .new], context: nil)
}

func unObserveKVO(keyPath: String) {
    if let index = observedPaths.index(of: keyPath) {
        observedPaths.remove(at: index)
    }
    removeObserver(self, forKeyPath: keyPath)
}

func unObserveAllKVO() {
    for keyPath in observedPaths {
        removeObserver(self, forKeyPath: keyPath)
    }
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if let keyPath = keyPath {
        switch keyPath {
        case #keyPath(camera.iso):
            slider.value = camera.iso
        default:
            break
        }
    }
}

I had used KVO in this way in Swift 3. You can use this code with few changes.

我在Swift 3中使用了KVO。您可以使用此代码,只需做一些更改。

#10


1  

Another example for anyone who runs into a problem with types such as Int? and CGFloat?. You simply set you class as a subclass of NSObject and declare your variables as follows e.g:

对于任何遇到类型(如Int)问题的人来说,这是另一个例子。和CGFloat ?。您只需将类设置为NSObject的子类并声明变量如下:

class Theme : NSObject{

   dynamic var min_images : Int = 0
   dynamic var moreTextSize : CGFloat = 0.0

   func myMethod(){
       self.setValue(value, forKey: "\(min_images)")
   }

}