我有以下代码,它在两个属性上添加了一个观察者:
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)很管用,但我不喜欢复制。我试图传递一个KeyPaths列表:
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
有这样的事吗?
发布于 2019-01-03 22:56:04
首先,请记住,KVO只适用于NSObject (或子类)的实例。因此,如果CirclePolygon的CirclePolygon属性是CGPoint或其他struct,则在尝试注册\CirclePolygon.origin.x观察者时会出现运行时错误,因为KVO不能应用于CGPoint的x属性。
第二,您给出的关键路径有不同的类型。假设(针对我的第一点),您希望观察radius ( Double)和origin ( 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>的对象,作为observe(_:options:changeHandler:)方法的keyPath参数。不幸的是,这种方法是声明如下
公共函数观察(_ keyPath: KeyPath,options: NSKeyValueObservingOptions = [],changeHandler:@EX之外(Self,NSKeyValueObservedChange) -> Void) -> NSKeyValueObservation
也就是说,这个方法需要一个KeyPath<Self, Value>,但是您要传递一个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),
]
}https://stackoverflow.com/questions/54029574
复制相似问题