swift 协议

2023-11-22 09:16:15 浏览数 (2)

协议规定了用来实现某一特定功能所必需的方法和属性

协议语法

代码语言:javascript复制
protocol SomeProtocol {
    // 这里是协议的定义部分
}

//拥有父类的类在遵循协议时,应该将父类名放在协议名之前
class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
    // 这里是类的定义部分
}

对属性、方法的规定

  • 协议中的只能用var来声明变量属性,还必须指明是只读的还是可读可写的,用{ set get }来表示属性是可读可写的,只读属性则用{ get }来表示
代码语言:javascript复制
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 关键字
代码语言:javascript复制
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修饰符
代码语言:javascript复制
protocol ClassAProtocol{
    init(a:Int)
}

class ClassA:ClassAProtocol{
    required init(a: Int) {
        print(a)
    }
}

let a = ClassA.init(a: 3)
  • 如果一个子类重写了父类的指定构造器,并且该构造器满足了某个协议的要求,那么该构造器的实现需要同时标注 required 和 override 修饰符
代码语言:javascript复制
protocol ClassAProtocol{
    init()
}

class ClassA{
    init() {
        
    }
}

class ClassB:ClassA,ClassAProtocol{
    
    // 因为遵循协议,需要加上 required
    // 因为继承自父类,需要加上 override
    required override init() {
        
    }
}

协议作为类型

  • 协议本身并不实现任何功能,但是协议可以被当做类型来使用
  • 协议是一种类型,与其他类型(例如 Int,Double,String)的写法相同,使用大写字母开头的驼峰式写法
  • 使用场景
    • 作为函数、方法或构造器中的参数类型或返回值类型
    • 作为常量、变量或属性的类型
    • 作为数组、字典或其他容器中的元素类型
代码语言:javascript复制
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 这样的格式进行组合,称为 协议合成

代码语言:javascript复制
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! 将实例强制向下转换到某个协议类型,如果强转失败,会引发运行时错误
代码语言:javascript复制
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关键字作为前缀来定义可选要求
代码语言:javascript复制
@objc protocol PlayProtocol{
    func playGame()
    @objc optional func run()
}

0 人点赞