首先,请记住 KVO 仅适用于NSObject
(或子类)的实例。因此,如果 的origin
属性CirclePolygon
是 aCGPoint
或其他属性,struct
当您尝试注册 的观察者时会出现运行时错误\CirclePolygon.origin.x
,因为 KVO 无法应用于x
a 的属性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),
]
}