协议规定了用来实现某一特定功能所必需的方法和属性
协议语法
代码语言:javascript复制protocol SomeProtocol {
// 这里是协议的定义部分
}
//拥有父类的类在遵循协议时,应该将父类名放在协议名之前
class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
// 这里是类的定义部分
}
对属性、方法的规定
- 协议中的只能用
var
来声明变量属性,还必须指明是只读的还是可读可写的,用{ set get }
来表示属性是可读可写的,只读属性则用{ get }
来表示
protocol ClassAProtocol {
var str: String {get set} // 继承他的时候不一定非要是计算型属性
var str1: String {get} // 只读
func log() -> String
}
class ClassA: ClassAProtocol {
var str = "000"
var str1 = "111"
func log() -> String {
return str
}
}
var a: ClassA = ClassA()
print(a.log())
var ap: ClassAProtocol = a //ClassAProtocol类型可以存放其子类
a.str = "666" // 不报错,因为a是可读可写的
ap.str1 = "888" // 报错,a因为a不可读
Mutating 方法要求
- 在协议中定义了一个属性,该方法会改变遵循该协议的类型的实例,那么在定义协议时需要在方法前加
mutating
关键字 - 实现协议中的
mutating
方法时,若是类类型,则不用写mutating
关键字。而对于结构体和枚举,则必须写mutating
关键字
protocol ClassAProtocol{
var str:String{get set}
}
struct ClassA:ClassAProtocol{
var str: String = "000"
mutating func change(value:String) {
str = value
}
}
let a = ClassA.init()
a.str
对构造器要求
- 可以在遵循该协议的类中实现构造器,并指定其为类的指定构造器或者便利构造器。在这两种情况下,你都必须给构造器实现标上
required
修饰符
protocol ClassAProtocol{
init(a:Int)
}
class ClassA:ClassAProtocol{
required init(a: Int) {
print(a)
}
}
let a = ClassA.init(a: 3)
- 如果一个子类重写了父类的指定构造器,并且该构造器满足了某个协议的要求,那么该构造器的实现需要同时标注 required 和 override 修饰符
protocol ClassAProtocol{
init()
}
class ClassA{
init() {
}
}
class ClassB:ClassA,ClassAProtocol{
// 因为遵循协议,需要加上 required
// 因为继承自父类,需要加上 override
required override init() {
}
}
协议作为类型
- 协议本身并不实现任何功能,但是协议可以被当做类型来使用
- 协议是一种类型,与其他类型(例如 Int,Double,String)的写法相同,使用大写字母开头的驼峰式写法
- 使用场景
- 作为函数、方法或构造器中的参数类型或返回值类型
- 作为常量、变量或属性的类型
- 作为数组、字典或其他容器中的元素类型
protocol ClassProtocol {
func log() -> String
}
class ClassA:ClassProtocol{
func log() -> String {
return "classA"
}
}
class ClassB:ClassProtocol{
func log() -> String {
return "classB"
}
}
struct ClassC{
var pro:ClassProtocol //协议作为属性
func run() -> String {
return self.pro.log()
}
}
let c = ClassC.init(pro: ClassA())
c.run() //classA
代理模式
代码语言:javascript复制protocol DosomethingProtocol {
func buy()
func share()
}
import UIKit
class APP: NSObject,DosomethingProtocol {
func buy() {
print("buy")
}
func share() {
print("share")
}
}
---------------------
import UIKit
class Student: NSObject {
var delegate:DosomethingProtocol?
}
-----------------------
let stu = Student()
let app = APP()
stu.delegate = app
stu.delegate!.share()
通过分类为现有类型添加属性、方法等等
代码语言:javascript复制protocol DosomethingProtocol {
func buy()
func share()
}
extension APP:DosomethingProtocol{
func buy() {
print("buy")
}
func share() {
print("share")
}
}
import UIKit
class APP: NSObject {
var name:String?
func study() {
print("study")
}
}
协议的继承
代码语言:javascript复制protocol DosomethingProtocol {
func buy()
func share()
}
protocol PlayProtocol:DosomethingProtocol {
func play()
}
extension APP:PlayProtocol{
func buy() {
print("buy")
}
func share() {
print("share")
}
func play() {
print("Play")
}
}
import UIKit
class APP: NSObject {
var name:String?
func study() {
print("study")
}
}
let app = APP.init()
app.name = "app"
app.study()
app.share()
app.buy()
app.play()
类类型专属协议
在协议的继承列表中,通过添加 class
关键字来限制协议只能被类类型遵循,而结构体或枚举不能遵循该协议。class
关键字必须第一个出现在协议的继承列表中,在其他继承的协议之前
类型专属协议.png
协议合成
需要同时遵循多个协议,可以将多个协议采用 Protocol & Protocol
这样的格式进行组合,称为 协议合成
protocol PlayProtocol{
func playGame()
}
protocol StudyProtocol {
func study()
}
class Boy:PlayProtocol,StudyProtocol{
func playGame() {
print("play")
}
func study() {
print("study")
}
func log(info:PlayProtocol&StudyProtocol) {
self.playGame()
self.study()
}
}
let boy = Boy()
boy.log(info: boy)
//play
//study
检查协议一致性
- is 用来检查实例是否符合某个协议,若符合则返回 true,否则返回 false。
- as? 返回一个可选值,当实例符合某个协议时,返回类型为协议类型的可选值,否则返回 nil。
- as! 将实例强制向下转换到某个协议类型,如果强转失败,会引发运行时错误
protocol PlayProtocol{
func playGame()
}
class Stu1:PlayProtocol{
func playGame() {
print("play")
}}
class Stu2:PlayProtocol{
func playGame() {
print("play")
}
}
class Stu3{
}
let stu1 = Stu1()
let stu2 = Stu2()
let stu3 = Stu3()
stu1 is PlayProtocol //true
stu2 is PlayProtocol //true
stu3 is PlayProtocol
stu1 as? PlayProtocol //true
stu2 as? PlayProtocol //true
stu3 as? PlayProtocol //nil
可选协议
- 协议和可选要求都必须带上
@objc
属性 - 在协议中使用
optional
关键字作为前缀来定义可选要求
@objc protocol PlayProtocol{
func playGame()
@objc optional func run()
}