观察Swift键路径列表

时间:2019-01-03 20:47:40

标签: swift swift-keypath

我有以下代码,在两个属性上添加了一个观察者:

    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

反正有这样做吗?

1 个答案:

答案 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>