http://www.hangge.com/blog/cache/detail_1823.html
一、Key Paths 新语法
key-path 通常是用在键值编码(KVC)与键值观察(KVO)上的,KVC、KVO 相关内容可以参考我之前写的这篇文章:Swift - 反射(Reflection)的介绍与使用样例(附KVC介绍)
1,Swift3 之前使用的是 String 类型的 key-Path
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | //用户类 class User : NSObject { @objc var name: String = "" //姓名 @objc var age: Int = 0 //年龄 } //创建一个User实例对象 let user1 = User () user1.name = "hangge" user1.age = 100 //使用KVC取值 let name = user1.value(forKey: "name" ) print (name) //使用KVC赋值 user1.setValue( "hangge.com" , forKey: "name" ) |
2,到了 Swift3 新增了 #keyPath() 写法
使用 #keyPath() 写法,可以避免我们因为拼写错误而引发问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | //用户类 class User : NSObject { @objc var name: String = "" //姓名 @objc var age: Int = 0 //年龄 } //创建一个User实例对象 let user1 = User () user1.name = "hangge" user1.age = 100 //使用KVC取值 let name = user1.value(forKeyPath: #keyPath( User .name)) print (name) //使用KVC赋值 user1.setValue( "hangge.com" , forKeyPath: #keyPath( User .name)) |
3,Swift4 中直接用 \ 作为开头创建 KeyPath
新的方式不仅使用更加简单,而且有如下优点:
- 类型可以定义为 class、struct
- 定义类型时无需加上 @objc 等关键字
- 性能更好
- 类型安全和类型推断,例如:user1.value(forKeyPath: #keyPath(User.name)) 返回的类型是 Any,user1[keyPath: \User.name] 直接返回 String 类型
- 可以在所有值类型上使用
(1)比如上面的样例在 Swift4 中可以这么写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | //用户类 class User : NSObject { var name: String = "" //姓名 var age: Int = 0 //年龄 } //创建一个User实例对象 let user1 = User () user1.name = "hangge" user1.age = 100 //使用KVC取值 let name = user1[keyPath: \ User .name] print (name) //使用KVC赋值 user1[keyPath: \ User .name] = "hangge.com" |
(2)keyPath 定义在外面也是可以的:
1 2 3 4 5 6 | let keyPath = \ User .name let name = user1[keyPath: keyPath] print (name) user1[keyPath: keyPath] = "hangge.com" |
(3)可以使用 appending 方法向已定义的 Key Path 基础上填加新的 Key Path。
1 2 | let keyPath1 = \ User .phone let keyPath2 = keyPath1.appending(path: \.number) |
二、类与协议的组合类型
在 Swift4 中,可以把类(Class)和协议(Protocol)用 & 组合在一起作为一个类型使用。
使用样例1:
1 2 3 4 5 6 7 8 9 10 11 12 13 | protocol MyProtocol { } class View { } class ViewSubclass : View , MyProtocol { } class MyClass { var delegate: ( View & MyProtocol )? } let myClass = MyClass () myClass.delegate = ViewSubclass () //这个编译正常 myClass.delegate = View () //这个编译报错: |
具体错误信息如下:
使用样例2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | protocol Shakeable { func shake() } extension UIButton : Shakeable { func shake() { /* ... */ } } extension UISlider : Shakeable { func shake() { /* ... */ } } func shakeEm(controls: [ UIControl & Shakeable ]) { for control in controls where control.isEnabled { control.shake() } } |
原文出自:www.hangge.com 转载请保留原文链接:http://www.hangge.com/blog/cache/detail_1823.html