当前位置: > > > Swift - Swift4新特性介绍1(Key Paths新语法、类与协议的组合类型)

Swift - Swift4新特性介绍1(Key Paths新语法、类与协议的组合类型)

一、Key Paths 新语法

key-path 通常是用在键值编码(KVC)与键值观察(KVO)上的,KVCKVO 相关内容可以参考我之前写的这篇文章:Swift - 反射(Reflection)的介绍与使用样例(附KVC介绍)

1,Swift3 之前使用的是 String 类型的 key-Path

//用户类
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() 写法,可以避免我们因为拼写错误而引发问题。
//用户类
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

新的方式不仅使用更加简单,而且有如下优点:
  • 类型可以定义为 classstruct
  • 定义类型时无需加上 @objc 等关键字
  • 性能更好
  • 类型安全和类型推断,例如:user1.value(forKeyPath: #keyPath(User.name)) 返回的类型是 Anyuser1[keyPath: \User.name] 直接返回 String 类型
  • 可以在所有值类型上使用

(1)比如上面的样例在 Swift4 中可以这么写:
//用户类
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 定义在外面也是可以的:
        let keyPath = \User.name
        
        let name = user1[keyPath: keyPath]
        print(name)

        user1[keyPath: keyPath] = "hangge.com"

(3)可以使用 appending 方法向已定义的 Key Path 基础上填加新的 Key Path
let keyPath1 = \User.phone
let keyPath2 = keyPath1.appending(path: \.number)

二、类与协议的组合类型

Swift4 中,可以把类(Class)和协议(Protocol)用 & 组合在一起作为一个类型使用。

使用样例1:

protocol MyProtocol { }

class View { }

class ViewSubclass: View, MyProtocol { }

class MyClass {
    var delegate: (View & MyProtocol)?
}

let myClass = MyClass()
myClass.delegate = ViewSubclass() //这个编译正常
myClass.delegate = View() //这个编译报错:

具体错误信息如下:

使用样例2:

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()
    }
}
评论2
  • 2楼
    2018-01-02 16:01
    Xiaopao

    我找到问题了,自己打的KeyPathd的k是大写的,你这边是小写的keyPath

    站长回复

    哦,你不说我还真没发现。

  • 1楼
    2017-12-18 21:21
    xiaopao

    俩个有什么区别吗?
    我手打的: user1[KeyPath: \ User.name] = "" //error :Type 'User' has no subscript members
    拷贝你的: user1[keyPath: \User.name] = "hangge.com"

    站长回复

    你User对象怎么定义的,里面有name这个属性吗?