协议定义了一个蓝图,规定了用来实现某一特定任务或者功能的方法、属性、以及其他需要的东西。
协议的语法
1 | protocol SomeProtocol { |
属性要求
协议可以要求遵循的类型提供特定名称和类型的实例属性或类型属性。协议不知道是存储属性还是计算属性,它指定属性的名称和类型
1 | protocol SomeProtocol { |
1 | //遵循次协议必须有一个可读String类型的实例属性fullName |
方法要求
在协议中定义类方法的时候,总是使用static 关键字作为前缀。当类类型遵循协议时,除了static关键字,还可以使用class关键字
1 | protocol SomeProtocol { |
异变方法要求
有时候需要在方法中改变方法所属的实例。例如,在值类型的实例方法中,将mutating
关键字作为方法的前缀,写在func关键字之前,表示可以在该方法中修改所属的实例以及实例任意属性的值。
注意:
实现协议中的mutating方法时,若是类类型,则不用写mutating关键字。而对于结构体和枚举,则必须mutating关键字
1 | protocol Togglable { |
构造器要求
协议可以要求遵循协议类型实现指定构造器。
1 | protocol SomeProtocol { |
协议构造器要求的类实现
你可以遵循协议的类中实现构造器,无论作为指定构造器还是便利构造器,都必须为构造器标上required修饰符
1 | class SomeClass : SomeProtocol { |
可失败构造器要求
协议还可为遵循协议类型的类型定义可失败构造器
协议作为类型
协议本身并不实现任何功能,但是协议可以被当做一个成熟的类型来使用。协议可以像其他普通类型一样使用。
- 作为函数、方法或构造器中的参数类型或返回值类型
- 作为常量、变量或属性的类型
- 作为数组、字典或其他容器的元素类型
1 | protocol RandomNumberGenerator { |
委托 现实中最常见的用法
委托是一种设计模式,它允许类或结构体将一些需要它们负责的功能委托给其他类型的实例。
在扩展里添加协议遵循
扩展可以为已有类型添加属性(计算属性)、方法、下标以及构造器,
1 | extersion SomeClass: SomeProtocol { |
有条件地遵循协议
泛型类型可能只在某些情况下满足一个协议的要求,比如当类类型的泛型形式参数遵循对应协议时。你可以通过扩展类型列出限制泛型类型有条件的遵循某协议。在你采纳协议的名字后面写泛型where分句。
1 | protocol SomeProtocol { |
在扩展里声明采纳协议
当一个类型已经符合了某个协议中的所有要求,却还没有声明采纳该协议时。可以通过空扩展体的扩展采纳该协议。
1 | struct Hamster { |
注意:即使满足了协议的所有要求,类型也不会自动遵循协议,必须显示地遵循协议
协议类型的集合
1 | //集合中的3个元素都遵循SomeProtocol协议的实例 |
协议继承
协议能够继承一个或多个其他协议
1 | protocol SomeProtocol: FirstProtocol,AnthorProtocol { |
类专属的协议
通过添加AnyObject 关键字到协议的继承列表,就可以限制协议只能被类类型采纳。
protocol SomeClassProtcol: class {
//专属类的协议定义部分
}
协议合成
要求一个类型同时遵循多个协议是很有用的。你可以使用协议组合来复合多个协议到一个要求里。
协议组合使用 SomeProtocol & AnotherProtocol 的形式。
1 | protocol Named { |
1 | class Location { |
检查协议一致性
is
和as
操作符来检查协议一致性,即是否复合某协议,并且可以转换到指定的协议类型。
- is 用来检查实例是否复合某个协议
- as? 返回一个可选值,当实例复合某个协议是,返回类型为协议类型的可选值。
- as! 将实例强制向下转换到某个协议,如果转换失败,会引发运行时错误
可选的协议要求
协议可以定义可选要求,遵循协议类型可以选择是否实现这些要求。协议中使用 optional 关键字作为前缀来定义可选要求。可选要求用在你需要和Objective-C打交道的代码中。协议和可选要求都必须带上 @objc
属性。标记 @objc
特性的协议只能被继承自 Objective-C类或者遵循。
使用可选要求时,他们的类型会自动变成可选的。比如,一个类型为 (Int) -> String 的方法会变成 ((Int) -> String)? ,这里是函数类型可选,不是函数的返回值可选
协议扩展
协议可以通过扩展来为遵循协议的类型提供属性、方法以及下标的实现
1 | extension RandomNumberGenerator { |
通过协议扩展,所有遵循协议的类型,都能自动获得这个扩展所增加的方法实现,无需任何额外的修改
提供默认实现
可以通过协议扩展来为协议的属性、方法以及下标提供默认的实现。如果遵循协议的类型为这些要求提供了自己的实现,那么这些自定义实现将会替代扩展的默认实现被使用。
为协议扩展添加限制条件
在扩展协议的时候,可以指定一些限制条件,只有遵循协议的类型满足某些限制条件,才能获得协议扩展提供的默认实现。使用where
字句来描述
1 | extension Collection where Element: Equatable { |