我有以下代码,在两个属性上添加了一个观察者:
obs = []
let xa = self.observe(\CirclePolygon.radius, options: [.new]) { (op, ch) in
callback()
}
obs.append(xa)
let xb = self.observe(\CirclePolygon.origin.x, options: [.new]) { (op, ch) in
callback()
}
obs.append(xb)
它有效,但是我不喜欢这种重复。我试图传递一个KeyPath列表:
obs = []
let keyPaths = [\CirclePolygon.radius, \CirclePolygon.origin.x]
for keyPath in keyPaths {
let xa = self.observe(keyPath, options: [.new]) { (op, ch) in
callback()
}
obs.append(xa)
}
但是我得到了编译器错误:Generic parameter 'Value' could not be inferred
反正有这样做吗?
答案 0 :(得分:3)
首先,请记住,KVO仅适用于NSObject
(或子类)的实例。因此,如果origin
的{{1}}属性是CirclePolygon
或其他CGPoint
,则当您尝试注册{{ 1}},因为KVO无法应用于struct
的{{1}}属性。
第二,您给出的关键路径具有不同的类型。假设(为了解决我的第一点),您想观察\CirclePolygon.origin.x
(一个x
)和CGPoint
(一个radius
)。关键路径具有不同的类型:
Double
如果您尝试将它们放在单个数组中,而没有显式指定数组的类型,则Swift会得出如下结论:
origin
推论CGPoint
是因为\CirclePolygon.radius // type: KeyPath<CirclePolygon, Double>
\CirclePolygon.origin // type: KeyPath<CirclePolygon, CGPoint>
是let keyPaths = [\CirclePolygon.origin, \CirclePolygon.radius]
// deduced type of keyPaths: [PartialKeyPath<CirclePolygon>]
和[PartialKeyPath<CirclePolygon>]
的最接近的共同祖先。
因此,在循环遍历数组的PartialKeyPath<CirclePolygon>
循环中,您将传递静态类型为KeyPath<CirclePolygon, Double>
的对象作为KeyPath<CirclePolygon, CGPoint>
方法的for
参数。不幸的是,该方法是declared as follows:
PartialKeyPath<CirclePolygon>
这就是说,该方法需要一个keyPath
,但是您要传递一个observe(_:options:changeHandler:)
,因此Swift会产生错误。与围绕泛型类型问题的Swift错误一样,该错误不是很有帮助。
您无法通过强制转换解决此问题,因为您无法(例如)将public func observe<Value>(
_ keyPath: KeyPath<Self, Value>,
options: NSKeyValueObservingOptions = [],
changeHandler: @escaping (Self, NSKeyValueObservedChange<Value>) -> Void)
-> NSKeyValueObservation
强制转换为KeyPath<Self, Value>
。
一种解决方案可能是使用局部函数封装通用代码,如下所示:
PartialKeyPath<Self>