什么是KeyPath用于?

时间:2017-06-08 23:25:17

标签: swift foundation

在Swift 4中,许多基金会团队已经讨论过与Swift 3相比,使用keyPaths要容易得多。这就引出了一个问题......什么是keyPath?说真的,我找不到任何明确的资源。

2 个答案:

答案 0 :(得分:13)

Objective-C能够动态引用属性而不是直接引用属性。这些引用称为keypaths。它们与直接属性访问不同,因为它们实际上不会读取或写入值,它们只是将其存放起来以供使用。

让我们定义一个名为Cavaliers的结构和一个名为Player的结构,然后创建每个结构的一个实例:

// an example struct
struct Player {
    var name: String
    var rank: String
}

// another example struct, this time with a method
struct Cavaliers {
    var name: String
    var maxPoint: Double
    var captain: Player

    func goTomaxPoint() {
        print("\(name) is now travelling at warp \(maxPoint)")
    }
}

// create instances of those two structs
let james = Player(name: "Lebron", rank: "Captain")
let irving = Cavaliers(name: "Kyrie", maxPoint: 9.975, captain: james)

// grab a reference to the `goTomaxPoint()` method
let score = irving.goTomaxPoint

// call that reference
score()

最后一行创建了一个名为score的goTomaxPoint()方法的引用。问题是,我们无法创建对队长名称属性的引用,但keypath可以这样做。

let nameKeyPath = \Cavaliers.name
let maxPointKeyPath = \Cavaliers.maxPoint
let captainName = \Cavaliers.captain.name
let cavaliersName = irving[keyPath: nameKeyPath]
let cavaliersMaxPoint = irving[keyPath: maxPointKeyPath]
let cavaliersNameCaptain = irving[keyPath: captainName]

请使用Xcode 9或快照进行测试。

答案 1 :(得分:0)

Swift KVC

[Objective-C KVC]

KeyPath 是对类型的属性而非引用。它为语言增添了活力

其中有一些:

  • KeyPath<Root, Value> - 只读
  • WritableKeyPath<Root, Value> - var 属性的读/写
  • ReferenceWritableKeyPath<Root, Value> - 仅对引用类型进行读/写[About]
  • PartialKeyPath<Root>
  • AnyKeyPath

你会发现 KeyPath 用于快捷方式(例如排序、迭代、过滤)、KVO[Example]、MemoryLayout[Example]、SwiftUI 和其他更高级的功能

语法

class SomeClass {
    var v: String = "Hello World"
}

Pre Swift v4 - 速度慢且类型不安全

@objc //For example var v: String = "Hello world"
let keyPath = #keyPath(SomeClass.v) //keyPath is String Type
//read
someClass.value(forKeyPath: keyPath) //or forKey:
//write
someClass.setValue("Another string", forKeyPath: keyPath) //or forKey:
  • 从反斜杠 \ 开始
let someKeyPath = \SomeClass.v //KeyPath<SomeClass, String>
  • 如果有已知对象,您可以使用 \.
someClass.observe(\.v, options: .new) //someClass1.v
//read
let res = someClass[keyPath: \SomeClass.v]

//write
someClass[keyPath: \.v] = "Another string"