jon*_*ley 163 key-value-observing swift
如果是这样,在Objective-C中使用键值观察时是否存在其他不存在的关键差异?
Rob*_*Rob 146
您可以在Swift中使用KVO,但仅限于子类的dynamic属性NSObject.考虑一下你想要观察bar一个Foo类的属性.在Swift 4中,在子类中指定bar为dynamicproperty NSObject:
class Foo: NSObject {
@objc dynamic var bar = 0
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以注册以观察bar属性的更改.在Swift 4和Swift 3.2中,这已大大简化,如在Swift中使用键值观察中所述:
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)")
}
}
}
Run Code Online (Sandbox Code Playgroud)
注意,在Swift 4中,我们现在使用反斜杠字符(这\.bar是bar被观察对象的属性的键路径)强键入键路径.此外,因为它使用了完成闭包模式,所以我们不必手动删除观察者(当token范围超出范围时,观察者就会被移除),super如果密钥没有,我们也不必担心调用实现比赛.只有在调用此特定观察者时才会调用闭包.有关更多信息,请参阅WWDC 2017视频,基金会的新功能.
在Swift 3中,为了观察它,它有点复杂,但与Objective-C中的相似.也就是说,你应该实现observeValue(forKeyPath keyPath:, of object:, change:, context:)哪个(a)确保我们处理我们的上下文(而不是我们的super实例注册要观察的东西); 然后(b)根据需要处理或传递给super实施.并确保在适当的时候以观察者身份移除自己.例如,您可以在取消分配时删除观察者:
在Swift 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])")
}
}
Run Code Online (Sandbox Code Playgroud)
注意,您只能观察可以在Objective-C中表示的属性.因此,您无法观察泛型,Swift struct类型,Swift enum类型等.
有关Swift 2实现的讨论,请参阅下面的原始答案.
使用dynamic关键字实现带子NSObject类的KVO 在使用Swift with Cocoa和Objective-C指南的采用可可设计约定章节的键值观察部分中描述:
键值观察是一种机制,允许对象通知其他对象的指定属性的更改.只要类继承自类,您就可以对Swift类使用键值观察
NSObject.您可以使用这三个步骤在Swift中实现键值观察.
将
dynamic修改器添加到要观察的任何属性.有关更多信息dynamic,请参阅需要动态调度.Run Code Online (Sandbox Code Playgroud)class MyObjectToObserve: NSObject { dynamic var myDate = NSDate() func updateDate() { myDate = NSDate() } }创建全局上下文变量.
Run Code Online (Sandbox Code Playgroud)private var myContext = 0为key-path添加一个观察者,并覆盖该
observeValueForKeyPath:ofObject:change:context:方法,然后删除中的观察者deinit.Run Code Online (Sandbox Code Playgroud)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) } }
[注意,此KVO讨论随后已从使用Swift with Cocoa和Objective-C指南中删除,该指南已针对Swift 3进行了修改,但它仍然按照本答案顶部的说明进行操作.
值得注意的是,Swift有自己的本地属性观察器系统,但这是指定一个类,它将在观察自己的属性时执行.另一方面,KVO旨在注册以观察某些其他类的某些动态属性的变化.
Cat*_*Man 105
是的,不是.KVO对NSObject子类的工作原理与它一如既往.它不适用于没有NSObject子类的类.斯威夫特(目前至少)没有自己的原生观察系统.
(请参阅有关如何将其他属性公开为ObjC的注释,以便KVO对其进行处理)
有关完整示例,请参阅Apple文档.
sla*_*zyk 91
是和否:
是的,您可以在Swift中使用相同的旧KVO API来观察Objective-C对象.
您还可以观察dynamic继承自的Swift对象的属性NSObject.
但是...... 不,它没有强烈打字,因为你可以期待Swift原生观察系统.
使用Swift与Cocoa和Objective-C | 关键价值观察
不,目前没有任意Swift对象的内置值观测系统.
是的,有内置的Property Observers,它们是强类型的.
但是...... 不,它们不是KVO,因为它们只允许观察对象自己的属性,不支持嵌套观察("关键路径"),你必须明确地实现它们.
Swift编程语言| 财产观察员
是的,您可以实现显式值观察,它将是强类型的,并允许从其他对象添加多个处理程序,甚至支持嵌套/"键路径".
但是...... 不,它不会是KVO,因为它只适用于你实现为可观察的属性.
您可以在此处找到用于实现此类值观察的库:
Observable-Swift - 用于Swift的KVO - 值观察和事件
Pau*_*son 10
一个例子可能对此有所帮助.如果我有一个实例model类的Model使用属性name和state我可以观察到这些属性:
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)
Run Code Online (Sandbox Code Playgroud)
对这些属性的更改将触发对以下内容的调用:
override func observeValueForKeyPath(keyPath: String!,
ofObject object: AnyObject!,
change: NSDictionary!,
context: CMutableVoidPointer) {
println("CHANGE OBSERVED: \(change)")
}
Run Code Online (Sandbox Code Playgroud)
是.
KVO需要动态分派,因此您只需将dynamic修饰符添加到方法,属性,下标或初始化程序中:
dynamic var foo = 0
该dynamic修改确保对声明的引用将被动态调度,并通过访问objc_msgSend.
除了Rob的回答.该类必须继承NSObject,并且我们有3种方法来触发属性更改
使用setValue(value: AnyObject?, forKey key: String)从NSKeyValueCoding
class MyObjectToObserve: NSObject {
var myDate = NSDate()
func updateDate() {
setValue(NSDate(), forKey: "myDate")
}
}
Run Code Online (Sandbox Code Playgroud)
使用willChangeValueForKey和didChangeValueForKey来自NSKeyValueObserving
class MyObjectToObserve: NSObject {
var myDate = NSDate()
func updateDate() {
willChangeValueForKey("myDate")
myDate = NSDate()
didChangeValueForKey("myDate")
}
}
Run Code Online (Sandbox Code Playgroud)
使用dynamic.请参阅Swift类型兼容性
您还可以使用动态修饰符来要求通过Objective-C运行时动态调度成员访问,如果您使用的是键值观察等动态替换方法实现的API.
class MyObjectToObserve: NSObject {
dynamic var myDate = NSDate()
func updateDate() {
myDate = NSDate()
}
}
Run Code Online (Sandbox Code Playgroud)
使用时会调用属性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
}
}
}
Run Code Online (Sandbox Code Playgroud)
目前Swift不支持任何内置机制来观察"self"以外的对象的属性更改,所以不,它不支持KVO.
然而,KVO是Objective-C和Cocoa的基本组成部分,它很可能会在将来添加.目前的文件似乎暗示了这一点:
关键价值观察
即将发布的信息.
| 归档时间: |
|
| 查看次数: |
101384 次 |
| 最近记录: |