Swift 4对KeyPath做了很大的改进。改进后的为类型安全的KeyPath。
Swift 2的KeyPath
示例
class Person: NSObject {
var name: String = ""
init(name: String) {
self.name = name
}
}
let me = Person(name: "张三")
me.valueForKeyPath("name")
Swift 2的KeyPath为一个字符串。显然,使用字符串作为KeyPath很容易造成拼写错误。
Swift 3的KeyPath
鉴于使用字符串作为keypath的值很容易造成拼写错误,Swift 3新增了#keyPath()来增强KeyPath的类型安全。
class Person: NSObject {
var name: String = ""
init(name: String) {
self.name = name
}
}
let me = Person(name: "张三")
me.value(forKeyPath: #keyPath(Person.name))
Swift 4新的KeyPath
虽然Swift 3新增了#keyPath()来对KeyPath做类型检查,但是检查后返回的仍然是字符串。
Swift 3的KeyPath有以下几个缺点
- 丢失了类型信息(因为#keyPath()返回的仍然是字符串,做KeyPath的所有类型都是Any)
- 需要对#keyPath()检查后返回的字符串做没必要的解析
- KeyPath只能应用于NSObject
- 局限于Darwin平台
Swift 4新引入了反斜杠"\"来表示KeyPath,其语法为:
- \<Type>.<path>
- \.<path>
<Type>:类型名
<path>:由一个或以上的属性构成的路径链,即property.property.....
如果可以推断出KeyPath对应的类型可以使用点号"\."开头,省略类型名。
Smart KeyPaths: Better Key-Value Coding for Swift的示例
class Person {
var name: String
var friends: [Person] = []
var bestFriend: Person? = nil
init(name: String) {
self.name = name
}
}
var han = Person(name: "Han Solo")
var luke = Person(name: "Luke Skywalker")
luke.friends.append(han)
简单的KeyPath:Person.name
let hanName = han[keyPath:\.name] //Han Solo
取得数组的KeyPath
let firstFriendsNameKeyPath = \Person.friends[0].name
let firstFriend = luke[keyPath: firstFriendsNameKeyPath] // "Han Solo"
// 等同于
luke[keyPath: \.friends[0].name] // "Han Solo"
//等同于
luke.friends[keyPath: \.[0].name] // "Han Solo"
//等同于
luke.friends[keyPath: \[Person].[0].name] // "Han Solo"
使用KeyPath修改属性值
// rename Luke's first friend
luke[keyPath: firstFriendsNameKeyPath] = "A Disreputable Smuggler"
可选属性的KeyPath
// optional properties work too
let bestFriendsNameKeyPath = \Person.bestFriend?.name
let bestFriendsName = luke[keyPath: bestFriendsNameKeyPath] // nil, if he is the last Jedi
参考:https://github.com/apple/swift-evolution/blob/master/proposals/0161-key-paths.md