KeyPath 的用途是什么?
What is a KeyPath used for?
在 Swift 4 中,基金会团队的许多人讨论了与 Swift 3 相比,使用 keyPaths 要容易得多。这引出了一个问题……什么是 keyPath?说真的,我找不到任何明确的资源。
Objective-C 能够动态引用 属性 而不是直接引用。这些引用称为键路径。它们与直接 属性 访问不同,因为它们实际上并不读取或写入值,它们只是将其存储起来以备使用。
让我们定义一个名为 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 或可用的快照进行测试。
Swift KVC
[Objective-C KVC]
KeyPath
是对 属性 类型的 reference 而不是 值。它为语言增添了活力
其中有一些:
KeyPath<Root, Value>
- 只读
WritableKeyPath<Root, Value>
- read/write 对于 var
属性
ReferenceWritableKeyPath<Root, Value>
- read/write 仅适用于引用类型[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"
在 Swift 4 中,基金会团队的许多人讨论了与 Swift 3 相比,使用 keyPaths 要容易得多。这引出了一个问题……什么是 keyPath?说真的,我找不到任何明确的资源。
Objective-C 能够动态引用 属性 而不是直接引用。这些引用称为键路径。它们与直接 属性 访问不同,因为它们实际上并不读取或写入值,它们只是将其存储起来以备使用。
让我们定义一个名为 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 或可用的快照进行测试。
Swift KVC
[Objective-C KVC]
KeyPath
是对 属性 类型的 reference 而不是 值。它为语言增添了活力
其中有一些:
KeyPath<Root, Value>
- 只读WritableKeyPath<Root, Value>
- read/write 对于var
属性ReferenceWritableKeyPath<Root, Value>
- read/write 仅适用于引用类型[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"