Swfit进阶-17-Swift协议的使用

186 阅读3分钟

「这是我参与2022首次更文挑战的第18天,活动详情查看:2022首次更文挑战」。

  • 本文主要介绍Swift中的协议的使用

1.协议与继承

我们定义2个类

class Person {

    var name = "jack"

    

}



class Dog {

    var name = "十六"

    var age = 3

    

    

}

在了解协议前我们可以看下下面的场景,我们为这2个类添加一个方法用来打印当前类的信息。我们可以把抽出来继承一个公共的类,公共类有debug的方法,子类可以调用。但是从业务逻辑上来说,这么处理不太合理。可能最直观的办法是对于每一个类都写一个单独的方法。

class Person {

    var name = "jack"
    func debug(){

        print(type(of: self))

    }
    

}

class Dog {

    var name = "十六"

    var age = 3
    func debug(){

        print(type(of: self))

    }

}

如果我们对当前代码中的每个类都需要 debug ,那上面这种方法显然是行不通的,于是我们有 了下面的代码

func debug(subject:AnyObject){

    print(type(of: subject))

}

当然看到这里可能大家也会觉得没有问题,如果我们要具体的描述当前类的具体信息,这个时候 我们还需要引入一个公共的基类,同时我们还需要有一个公共的属性 description 来让子类重 载,这无疑对我们的代码是很强的入侵。
所以这个时候我们通过一个协议来描述当前类的共同行为,并通过 extension 的方式来对我们 的类进行扩展

image.png

简单小结下:

  1. class类本质上定义了对象是什么
  2. protocol协议则是定义了对象有哪些行为

2. 协议的使用

  • 协议的委托 通常类,结构体,枚举都可以遵循协议,如果遵循多个协议则用,隔开

image.png

如果类有继承关系的话,放在协议之前

image.png

  • 协议添加属性

我们在协议中定义属性必须是可读的或者可读可写的,否则报错

protocol MyProtocol {

    var age:Int{get}//可读的

    var name:String{get set}//可读写的

}

image.png

属性必须要是var形容,不能用let

image.png

  • 协议添加方法
protocol MyProtocol {

    

    var age:Int{get}//可读的

    var name:String{get set}//可读写的

    

    static func test()//类方法

    func test1()

    func test2() ->Int//带返回值

    func test3(_ amount:Int)->Int//带参数



}
//实现
class Person :NSObject,MyProtocol{

    func test3(_ amount: Int) -> Int {

        

        return age+amount

    }

    

    var age: Int = 0

    

    static func test() {

            

    }

    

    func test1() {

        

    }

    

    func test2() -> Int {

        

        return age

    }

    

    var name = "jack"

}
let p = Person()

p.age = 20

p.test1()

print(p.test3(20)) 

Person.test()

方法中可以添加参数,也可以不添加返回值,也可以添加类方法。和我们在类中定义方法类似,只是不需要实现。如果我们需要某些方法是可选的,因为协议中方法默认是必须要实现的required

image.png

我们只需在协议前@objc修饰,在方法前@objc optional修饰。

  • 定义初始化方法,当实现初始化器时,必须使用required关键字

image.png

但是如果我们使用final修饰类的话,表示它不可继承,就不需要使用required修饰了

image.png

3. 协议的进阶使用

  • mutating 将协议中的实例方法标记为 mutating,才允许结构体、枚举的具体实现修改自身内存。类在实现方法时不用加 mutating,枚举、结构体才需要加 mutating
protocol PrintClassInfo {

    

   mutating func debug()

    

}

class Student: PrintClassInfo {

    

    func debug() {

        

        print("debug")

        

    }

}

struct MyStruct: PrintClassInfo{

    

    mutating func debug() {

        

        print("debug")

        

    }

    

}
  • 协议的继承 协议也可以继承别的协议,类继承后都可以实现协议的方法
protocol PrintClassInfo {

    

    func debug()

    

}

protocol PrintClassInfo1:PrintClassInfo {

    

    func printLog()

    

}

class Student: PrintClassInfo1 {

    

    

    func printLog() {

        

    }

    func debug() {

        

        print("debug")

        

    }

}
  • 专用协议 通过添加AnyObject关键字到协议的继承列表,你就可以限制协议只能被类的类型采纳

image.png