Ios KVO观察不适用于Swift泛型
如果我使用KVO观察属性,如果观察者是泛型类,那么我会收到以下错误: 对象的-observeValueForKeyPath:更改:上下文:消息为 已收到但未处理 下面的设置简洁地演示了这个问题。定义一些简单的类:Ios KVO观察不适用于Swift泛型,ios,generics,swift,key-value-observing,Ios,Generics,Swift,Key Value Observing,如果我使用KVO观察属性,如果观察者是泛型类,那么我会收到以下错误: 对象的-observeValueForKeyPath:更改:上下文:消息为 已收到但未处理 下面的设置简洁地演示了这个问题。定义一些简单的类: var context = "SomeContextString" class Publisher : NSObject { dynamic var observeMeString:String = "Initially this value" } class Subscr
var context = "SomeContextString"
class Publisher : NSObject {
dynamic var observeMeString:String = "Initially this value"
}
class Subscriber<T> : NSObject {
override func observeValueForKeyPath(keyPath: String,
ofObject object: AnyObject,
change: [NSObject : AnyObject],
context: UnsafeMutablePointer<Void>) {
println("Hey I saw something change")
}
}
var context=“SomeContextString”
类发布者:NSObject{
dynamic var observeMeString:String=“最初为该值”
}
类订户:NSObject{
重写函数observeValueForKeyPath(键路径:字符串,
ofObject对象:任何对象,
更改:[NSObject:AnyObject],
上下文:unsafemeutablepointer){
println(“嘿,我看到了一些变化”)
}
}
实例化它们并尝试使用订阅服务器观察发布服务器,如下所示(在空白项目的UIViewController子类中完成):
var pub=Publisher()
var sub=订户()
重写func viewDidLoad(){
super.viewDidLoad()
pub.addObserver(sub,forKeyPath:“observeMeString”,选项:。新建,上下文:&上下文)
pub.observeMeString=“现在该值”
}
如果我从类定义中删除泛型类型T,那么一切都可以正常工作,但否则我会得到“已接收但未处理的错误”。我是不是漏掉了什么明显的东西?我还需要做些什么,或者泛型不应该与KVO一起使用吗?解释
一般来说,有两个原因可以阻止特定的Swift类或方法在Objective-C中使用
第一个是纯Swift类使用C++风格的vtable分派,Objective-C不理解这一点。这在大多数情况下可以通过使用dynamic
关键字来克服,正如您显然理解的那样
第二个是,一旦引入泛型,Objective-C就失去了查看泛型类的任何方法的能力,直到它到达继承层次结构中祖先不是泛型的点为止。这包括引入的新方法以及覆盖
class Watusi : NSObject {
dynamic func watusi() {
println("watusi")
}
}
class Nguni<T> : Watusi {
override func watusi() {
println("nguni")
}
}
var nguni = Nguni<Int>();
这是因为
Subscriber
本身不是泛型的,只是它的init
方法。闭包用于对Objective-C“隐藏”泛型类型参数。不同的问题,但原因相同:
class Watusi : NSObject {
dynamic func watusi() {
println("watusi")
}
}
class Nguni<T> : Watusi {
override func watusi() {
println("nguni")
}
}
var nguni = Nguni<Int>();
class Subscriber : NSObject {
private let _observe : (String, AnyObject, [NSObject: AnyObject], UnsafeMutablePointer<Void>) -> Void
required init<T: NSObject>(obj: T, observe: ((T, String) -> Void)) {
_observe = { keyPath, obj, changes, context in
observe(obj as T, keyPath)
}
}
override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
_observe(keyPath, object, change, context)
}
}
class Publisher: NSObject {
dynamic var string: String = nil
}
let publisher = Publisher()
let subscriber = Subscriber(publisher) { _, _ in println("Something changed!") }
publisher.addObserver(subscriber, forKeyPath: "string", options: .New, context: nil)
publisher.string = "Something else!"