首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Swift 5存储和传递KeyPaths

Swift 5存储和传递KeyPaths
EN

Stack Overflow用户
提问于 2020-03-01 03:17:57
回答 1查看 1.2K关注 0票数 0

假设我有以下类:

代码语言:javascript
复制
class User: NSObject {
  var name = "Fred"
  var age = 24
  var email = "fred@freddy.com"
  var married = false
}

我希望能够编写一个泛型函数,它可以接收已知类类型的KeyPath列表,读取值并打印到屏幕上。问题是,我不能让下面的代码编译,因为KeyPathValue的类型是未知的,并且每次都是不同的。我必须做什么才能使它通用地工作?

请考虑以下几点:

代码语言:javascript
复制
struct KeyPathProperties<T> {
  var name: String
  var relatedKeyPaths: [KeyPath<T, Any>]
}

extension KeyPath where Root == User {
  var properties: KeyPathProperties<Root> {
    switch self {
      case \Root.name:
        return KeyPathProperties(name: "name", relatedKeyPaths: [\Root.age, \Root.email])
      default:
        fatalError("Unknown key path")
    }
  }
}

这一行无法编译:

代码语言:javascript
复制
return KeyPathProperties(name: "name", relatedKeyPaths: [\Root.age, \Root.email])

出现以下错误:

Cannot convert value of type 'KeyPath<User, Int>' to expected element type 'KeyPath<User, Any>'

例如,这是我希望能够做的事情:

代码语言:javascript
复制
let myUser = User()

var keyPathProps = KeyPathProperties(name: "name", relatedKeyPaths: [\User.age, \User.email])

for keyPath in props.relatedKeyPaths {
  print("Value: \(myUser[keyPath: keyPath])")
}

当然,上面的代码不能编译。本质上,我希望在运行时将keyPaths存储在一个数组中,这样我通常可以在某个时间点从User中获取值。我需要知道我是否可以用某种方式重写上面的代码,这样编译器就可以在运行时安全而正确地确定keyPath的值的类型。

这是一个更复杂的架构问题的概念性用例,我希望用更少的代码来解决。

更多信息:

在运行时,我希望跟踪修改的属性-这些属性保存在每个对象/实例的modifiedProps数组中。在运行时的某个时刻,我希望能够枚举这个KeyPaths数组并打印它们的值,如下所示:

代码语言:javascript
复制
for modifiedKeyPath in self.modifiedProps { 
  print ("\(self[keyPath: modifiedKeyPath])" 
}

简而言之,我需要能够在KeyPathProperties中捕获KeyPath的泛型类型。我该如何实现这一点?

附注:我已经可以通过使用基于Swift 3样式字符串的KeyPaths (通过将@objc添加到类属性)轻松地实现这一点。我可以将keyPaths数组存储为字符串,然后执行以下操作:

代码语言:javascript
复制
let someKeyPath = #keyPath(User.email)
...

myUser.value(forKeyPath: someKeyPath)

我一般不能用Swift 4 KeyPaths做到这一点。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-03-01 03:40:31

这个错误告诉你你的误解是什么:

代码语言:javascript
复制
Cannot convert value of type 'KeyPath<User, Int>' 
    to expected element type 'KeyPath<User, Any>'

您似乎认为可以在需要KeyPath<User, Any>的地方使用KeyPath<User, Int>,表面上是因为Int是Any。但事实并非如此。这些是泛型类型,并且泛型类型不是协变的-也就是说,没有基于其参数化类型的泛型的替换原则。这两种类型实际上是不相关的。

如果您需要一个键路径数组,而不考虑它们的参数化类型,那么您将需要一个PartialKeyPath或AnyKeyPath数组。在您的用例中,根对象似乎始终是相同的,因此您可能需要PartialKeyPath。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60468740

复制
相关文章

相似问题

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