首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >观察Swift KeyPaths列表

观察Swift KeyPaths列表
EN

Stack Overflow用户
提问于 2019-01-03 20:47:40
回答 1查看 893关注 0票数 4

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

代码语言:javascript
复制
    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列表:

代码语言:javascript
复制
    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

有这样的事吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-01-03 22:56:04

首先,请记住,KVO只适用于NSObject (或子类)的实例。因此,如果CirclePolygonCirclePolygon属性是CGPoint或其他struct,则在尝试注册\CirclePolygon.origin.x观察者时会出现运行时错误,因为KVO不能应用于CGPointx属性。

第二,您给出的关键路径有不同的类型。假设(针对我的第一点),您希望观察radius ( Double)和origin ( CGPoint)。关键路径有不同的类型:

代码语言:javascript
复制
\CirclePolygon.radius   // type: KeyPath<CirclePolygon, Double>
\CirclePolygon.origin   // type: KeyPath<CirclePolygon, CGPoint>

如果您试图将这些放在一个数组中,而不显式地指定数组的类型,Swift将推断它如下:

代码语言:javascript
复制
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>

一种解决方案可能是使用本地函数封装通用代码,如下所示:

代码语言:javascript
复制
func register(callback: @escaping () -> ()) -> [NSKeyValueObservation] {
    func r<Value>(_ keyPath: KeyPath<CirclePolygon, Value>) -> NSKeyValueObservation {
        return observe(keyPath, options: []) { (_, _) in
            callback()
        }
    }

    return [
        r(\.radius),
        r(\.origin),
    ]
}
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54029574

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档