0

假设我有以下课程:

class User: NSObject {
  var name = "Fred"
  var age = 24
  var email = "fred@freddy.com"
  var married = false
}

我希望能够编写一个通用函数,该函数接受KeyPath已知类类型的 s 列表,读取值并打印到屏幕。问题是,我无法编译以下代码,因为KeyPath's的类型Value未知,并且每次都会有所不同。我该怎么做才能使这项工作普遍进行?

考虑以下:

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")
    }
  }
}

此行无法编译:

return KeyPathProperties(name: "name", relatedKeyPaths: [\Root.age, \Root.email])

出现此错误:

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

这就是我希望能够做到的,例如:

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 数组并像这样打印它们的值:

for modifiedKeyPath in self.modifiedProps { 
  print ("\(self[keyPath: modifiedKeyPath])" 
}

简而言之 - 我需要能够在KeyPathProperties. 我如何实现这一目标?

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

let someKeyPath = #keyPath(User.email)
...

myUser.value(forKeyPath: someKeyPath)

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

4

1 回答 1

0

该错误告诉您您的误解是什么:

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

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

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

于 2020-02-29T19:40:31.077 回答