I have the following code which adds an observer on two properties:
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)
It works, but I don't like the duplciation. I have tried to pass a list of 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)
}
But I get the compiler error: Generic parameter 'Value' could not be inferred
Is there anyway to do this?
First of all, remember that KVO only works on instances of
NSObject(or a subclass). So if theoriginproperty ofCirclePolygonis aCGPointor some otherstruct, you'll get a run-time error when you try to register an observer of\CirclePolygon.origin.x, because KVO cannot apply to thexproperty of aCGPoint.Second, the key paths you gave have different types. Let's say (to address my first point) you want to observe
radius(aDouble) andorigin(aCGPoint). The key paths have different types:If you try to put these in a single array, without explicitly specifying the type of the array, Swift will deduce it as follows:
It deduces
[PartialKeyPath<CirclePolygon>]becausePartialKeyPath<CirclePolygon>is the nearest common ancestor of bothKeyPath<CirclePolygon, Double>andKeyPath<CirclePolygon, CGPoint>.So, in the
forloop where you iterate over the array, you're passing an object with static typePartialKeyPath<CirclePolygon>as thekeyPathargument of theobserve(_:options:changeHandler:)method. Unfortunately, that method is declared as follows:Which is to say, the method requires a
KeyPath<Self, Value>but you're passing aPartialKeyPath<Self>, so Swift emits an error. As is often the case with Swift errors around generic type problems, the error isn't very helpful.You cannot solve this problem by casting, because you cannot (for example) cast
KeyPath<CirclePolygon, Double>toKeyPath<CirclePolygon, Any>.One solution may be to use a local function to encapsulate the common code, like this: