首先,请记住 KVO 仅适用于NSObject(或子类)的实例。因此,如果 的origin属性CirclePolygon是 aCGPoint或其他属性,struct当您尝试注册 的观察者时会出现运行时错误\CirclePolygon.origin.x,因为 KVO 无法应用于xa 的属性CGPoint。
其次,您给出的关键路径有不同的类型。假设(为了解决我的第一点)您想要观察radius(a Double) 和origin(a CGPoint)。关键路径有不同的类型:
\CirclePolygon.radius // type: KeyPath<CirclePolygon, Double>
\CirclePolygon.origin // type: KeyPath<CirclePolygon, CGPoint>
如果你试图将它们放在一个数组中,而不明确指定数组的类型,Swift 将推导出它如下:
let keyPaths = [\CirclePolygon.origin, \CirclePolygon.radius]
// deduced type of keyPaths: [PartialKeyPath<CirclePolygon>]
它推断[PartialKeyPath<CirclePolygon>]因为PartialKeyPath<CirclePolygon>是 和 的最近共同KeyPath<CirclePolygon, Double>祖先KeyPath<CirclePolygon, CGPoint>。
因此,在for遍历数组的循环中,您将传递一个静态类型的对象PartialKeyPath<CirclePolygon>作为方法的keyPath参数observe(_:options:changeHandler:)。不幸的是,该方法声明如下:
public func observe<Value>(
_ keyPath: KeyPath<Self, Value>,
options: NSKeyValueObservingOptions = [],
changeHandler: @escaping (Self, NSKeyValueObservedChange<Value>) -> Void)
-> NSKeyValueObservation
也就是说,该方法需要 aKeyPath<Self, Value>但您传递的是 a PartialKeyPath<Self>,因此 Swift 会发出错误。与泛型类型问题的 Swift 错误一样,该错误并不是很有帮助。
你不能通过强制转换来解决这个问题,因为你不能(例如)强制转换KeyPath<CirclePolygon, Double>为KeyPath<CirclePolygon, Any>.
一种解决方案可能是使用本地函数来封装公共代码,如下所示:
func register(callback: @escaping () -> ()) -> [NSKeyValueObservation] {
func r<Value>(_ keyPath: KeyPath<CirclePolygon, Value>) -> NSKeyValueObservation {
return observe(keyPath, options: []) { (_, _) in
callback()
}
}
return [
r(\.radius),
r(\.origin),
]
}