Прежде всего, помните, что KVO работает только на экземплярах NSObject
(или подклассе).Поэтому, если origin
свойство CirclePolygon
является CGPoint
или каким-либо другим struct
, вы получите ошибку во время выполнения при попытке зарегистрировать наблюдателя на \CirclePolygon.origin.x
, поскольку KVO не может применяться кx
свойство 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
То есть метод требует 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),
]
}