美文网首页SwiftAPP & program
iOS开发 - 「Swift 学习」Swift协议

iOS开发 - 「Swift 学习」Swift协议

作者: 俺不是大佬儿 | 来源:发表于2022-04-08 11:31 被阅读0次

    Swift协议

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

    类、结构体、枚举类型都可以遵循协议,并提供具体实现来完成协议定义的方法和功能。
    能够满足协议要求的类型被称为遵循此协议

    (一)协议的声明\color{red}{(协议本身是不实现任何功能的)}

    协议的定义方式(关键词:protocol):

    protocol ProtocolName {
        // 协议内容(声明属性/方法)
    }
    

    协议对属性声明的规定

    协议用于指定特定的实例属性或类属性,而不用指定是存储型还是计算型的属性。必须要指明是只读的还是可读可写的属性

    通常用var关键词声名变量属性,在类型声明后面加{set get}表示是可读可写属性,用{get}表示只读属性

    protocol firstProtocol {
        //声明协议属性(可读可写)
        var english:Float{set get}
        var chinese:Double{set get}
        var mathematics:Double{set get}
        //声明协议方法
        func minResults() -> String
        func maxResults() -> String
    }
    //协议的继承
    protocol secondProtocol:firstProtocol{
         //声明只读型的协议属性
        var ranking:String{get}
        var name:String{get}
    }
    
    //FirstClass类遵循secondProtocol协议,需要FirstClass类实现secondProtocol协议中的属性及方法
    class FirstClass:secondProtocol {
        //实现协议中的只读属性
        let ranking = "第三名"
        let name = "小明"
        
        var english:Float = 78.50
        
        var chinese = 88.0
        
        var mathematics = 95.0
        
        func minResults() -> String {
            return "小明本次成绩数学是最高分95.0"
        }
        
        func maxResults() -> String {
            return "小明本次成绩最低分是英语78.5"
        }
    }
    

    调用

    let student = FirstClass()
    print("\(student.maxResults())")
    

    调用结果

    小明本次成绩最低分是英语78.5
    

    协议对构造器的声明

    协议是可以要求它的遵循者实现指定的构造器
    在协议的定义中\color{red}{只需要写下构造器的声明部分},不需要花括号及构造器的实体

    */
    protocol ProtocolName {
       init(someParameter: Int)
    }
    */
    
    protocol tcpprotocol {
        init (aprot:Int)
    }
    

    协议中对Mutating方法的规定

    若需要在方法中改变实例,例如,值类型(结构体,枚举)的实例方法中,将mutating关键字作为函数的前缀,写在func之前,表示可以在该方法中修改它所属的实例及其实例属性的值

    protocol daysofaweek {
        mutating func show()
    }
    
    enum days: daysofaweek {
        case sun, mon, tue, wed, thurs, fri, sat
        mutating func show() {
            switch self {
            case .sun:
                self = .sun
                print("Sunday")
            case .mon:
                self = .mon
                print("Monday")
            case .tue:
                self = .tue
                print("Tuesday")
            case .wed:
                self = .wed
                print("Wednesday")
            case .thurs:
                self = .thurs
                print("Wednesday")
            case .fri:
                self = .fri
                print("Firday")
            case .sat:
                self = .sat
                print("Saturday")
            default:
                print("NO Such Day")
            }
        }
    }
    

    调用

    var res = days.wed
    res.show()
    

    调用结果

    Wednesday
    

    (二)协议的实现

    协议构造器在类中的实现

    在遵循该协议的类中实现构造器,并指定其为类的指定构造器或便利构造器,必须给\color{red}{构造器的实现}"required"修饰

    //协议构造器的实现
    class SomeClass: ProtocolName {
       required init(someParameter: Int) {
          // 构造器实现
       }
    }
    
    protocol tcpprotocol {
        init (aprot:Int)
    }
    
    class tcpClass:tcpprotocol {
        required init(aprot: Int) {
            print("实现指定构造器方法")
        }
    }
    
    class TestMainClass {
        var num:Int//局部变量
        init(aprot:Int){
            self.num = aprot
        }
    }
    
    class TestSubClass:TestMainClass,tcpprotocol {
        var num2:Int
        init(num1:Int,num2:Int){
            self.num2 = num2
            super.init(aprot: num1)
        }
        //遵循协议,加上"required" 继承父类重写父类构造器加上"override"
        required override  convenience init(aprot: Int) {
            self.init(num1: aprot, num2: 10)
        }
    }
    

    调用

    let tcp = tcpClass(aprot: 3)
    print("实现协议方法:\(tcp)")
    

    调用结果

    实现指定构造器方法
    实现协议方法:Swift_study.tcpClass
    

    协议类型

    \color{red}{协议本身是不实现任何功能的},但是协议可以被当做类型使用
    \color{red}{✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧}
    \color{BlueViolet}{协议类型的使用场景:}
    \color{red}{✎} \color{BlueViolet}{作为函数、方法或构造器中的参数类型或返回值类型}
    \color{red}{✎} \color{BlueViolet}{作为常量、变量或属性的类型}
    \color{red}{✎} \color{BlueViolet}{作为数组、字典或其他容器中的元素类型}
    \color{red}{✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧✧}

    protocol TestProtocolA{
        var num:Int{get set}
        func calc(sum:Int)
    }
    
    protocol ResultProtocol{
    //将协议TestProtocolA作为定义方法时的参数类型
        func print(target: TestProtocolA)
    }
    
    class XiaoHong:ResultProtocol{
        func print(target: TestProtocolA) {
            target.calc(sum: 1)
        }
    }
    
    class XiaoQiang:ResultProtocol {
        func print(target: TestProtocolA) {
            target.calc(sum: 5)
        }
    }
    
    class DaMing:TestProtocolA {
        var num: Int = 10
        
        func calc(sum: Int) {
            num -= sum
            print("大明尝试\(sum)次通过")
        
            if num <= 0{
                print("大明缺席考试")
            }
        }
    }
    
    class Player {
        var stmark:ResultProtocol!
        
        init(stmark:ResultProtocol){
            self.stmark = stmark
        }
        
        func print(target:TestProtocolA){
            stmark.print(target: target)
        }
    }
    

    调用

    let marks = Player(stmark: XiaoHong())
    let marksec = DaMing()
    marks.print(target: marksec)
            
    marks.stmark = XiaoQiang()
    marks.print(target: marksec)
    marks.print(target: marksec)
    marks.print(target: marksec)
    

    调用结果

    大明尝试1次通过
    大明尝试5次通过
    大明尝试5次通过
    大明缺席考试
    大明尝试5次通过
    大明缺席考试
    

    在扩展中添加遵循的协议

    扩展可以为已存在的类型添加\color{DarkOrange}{属性、方法、下标脚本、} \color{red}{协议}等成员

    //在扩展中添加协议成员
    enum ageType
    {
        case Baby,Child,Teenager,Young,Elderly,Normal
    }
    
    protocol AgeClasificationProtocol {
        var age: Int { get }
        func agecClassified() -> ageType
    }
    
    //创建Actor类
    class Actor {
    
        let firstname:String
        let lastname:String
        //很神奇,对Actor扩展时增加了AgeClasificationProtocol协议,在此实现协议里的属性、方法也是可以的(也可以在扩展中实现)
        var age:Int
        init(firstname:String,lastname:String) {
            self.firstname = firstname;
            self.lastname = lastname;
            self.age = 13
        }
    }
    
    //对Actor类扩展时添加AgeClasificationProtocol协议
    extension Actor:AgeClasificationProtocol{
        
        func fullname() -> String {
            var name: String
            name = firstname + " " + lastname
            return name
        }
        
        //实现协议方法
        func agecClassified() -> ageType {
            switch age{
            case 0...2:
                return .Baby
            case 3...12:
                return .Child
            case 13...19:
                return .Teenager
            case 20...40:
                return .Young
            case let x where x > 65:
                return .Elderly
            default:
                return .Normal
            }
        }
        
        // () -> ageType 函数类型的参数
        func ageTypeName(typeFunc:() -> ageType) -> String {
            let type = typeFunc()
            
            switch type {
            case .Baby:
                return "婴儿"
            case .Child:
                return "小孩儿"
            case .Teenager:
                return "少年"
            case .Young:
                return "青年"
            case .Elderly:
                return "长者"
            default:
                return "未知"
            }
        }
    }
    

    调用

    let xiaoming = Actor(firstname: "王", lastname: "小明")
    xiaoming.age = 12
    let ageName = xiaoming.ageTypeName(typeFunc: xiaoming.agecClassified)
    print("演员的全名:\(xiaoming.fullname())")
    print("\(xiaoming.fullname()):所属的年龄段:\(ageName)")
    

    调用结果

    演员的全名:王 小明
    王 小明:所属的年龄段:小孩儿
    

    协议的继承

    协议是能够继承\color{red}{一个或者多个}其他协议,可以在继承的协议基础上增加新的内容要求。
    语法:协议的继承语法与类的继承相似,\color{red}{多个被继承的协议之间用逗号隔开}

    //protocol 新的协议名: 被继承的协议, 被继承的协议,其他被继承的协议 { // 增加的新的协议定义}
    protocol NewProtocolName: SomeInheritingProtocol, AnotherInheritingProtocol {
        // 增加的新的协议定义
    }
    

    protocol firstProtocol {
        
        var english:Float{set get}
        var chinese:Double{set get}
        var mathematics:Double{set get}
        
        func minResults() -> String
        func maxResults() -> String
    }
    
    protocol secondProtocol:firstProtocol{
        
        var ranking:String{get}
        var name:String{get}
    }
    
    
    class FirstClass:secondProtocol {
        
        let ranking = "第三名"
        
        let name = "小明"
        
        var english:Float = 78.50
        
        var chinese = 88.0
        
        var mathematics = 95.0
        
        func minResults() -> String {
            return "小明本次成绩数学是最高分95.0"
        }
        
        func maxResults() -> String {
            return "小明本次成绩最低分是英语78.5"
        }
    }
    

    调用

    let student = FirstClass()
    print("\(student.maxResults())")
    

    调用结果

    小明本次成绩最低分是英语78.5
    

    定义类的专属协议

    可以在协议的继承列表中,通过\color{red}{添加class关键字,限制协议只能适配到类(Class)类型}

    注意:class关键字必须是\color{red}{第一个出现在协议的继承列表中},其后,才是其他继承协议。

    protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
    // 协议的定义内容
    }

    protocol TcpProtocol {
        init(num:Int)
    }
    //用class修饰符在协议的继承列表中定义类的专属协议ExclusiveProtocol
    protocol ExclusiveProtocol:class,TcpProtocol{
        init(num1:Int,num2:Int)
    }
    //TcpProtocol协议可以被结构体遵循
    struct School:TcpProtocol{
        init(num: Int) {
            print("市第\(num)中学")
        }
    }
    //ExclusiveProtocol协议已经不能被结构体类型遵循了
    /*
    struct Hospital:ExclusiveProtocol {
        init(num: Int) {
            print("市第\(num)医院")
        }
    }
    */
    
    //Hospital类遵循专属协议ExclusiveProtocol
    class Hospital:ExclusiveProtocol{
        
        var area:Int
        var num:Int
        init(area: Int, num: Int) {
            self.area = area
            self.num = num
            print("\(area)区-\(num)号医院")
        }
    
        required convenience init(num1: Int, num2: Int) {
            self.init(area: num1, num: num2)
    
        }
    
        required convenience init(num: Int) {
            self.init(area: 5, num: num)
        }
    }
    
    
    class CityHospital:Hospital{
        var address:String
        init(address:String,area:Int,num:Int){
            self.address = address
            super.init(area: area, num: num)
            
            print("\(address)-\(area)区-\(num)号医院")
        }
        
        required convenience init(num1: Int, num2: Int) {
            self.init(address:"河北街",area: num1, num: num2)
        }
        
        required convenience init(num: Int) {
            self.init(address:"河东街",area: num, num: 10)
        }
    }
    

    调用

    let hospital = Hospital(num: 8);
    let hospital_a = CityHospital(address: "河西街", area: 1, num: 2)
    let hospital_b = CityHospital(num: 6)
    

    调用结果

    5区-8号医院
    1区-2号医院
    河西街-1区-2号医院
    6区-10号医院
    河东街-6区-10号医院
    

    协议的合成

    \color{red}{Swift支持合成多个协议},在需要同时遵循多个协议时很有用

    protocol NameProtocol {
        var name:String{get}
    }
    
    protocol AgeProtocol {
        var age:Int{get}
    }
    //Worker遵循俩协议
    struct Worker:NameProtocol,AgeProtocol {
        var name: String
        var age: Int
    }
    
    //NameProtocol & AgeProtocol合体
    func showWorker(worker:NameProtocol & AgeProtocol){
        print("\(worker.name) is \(worker.age) years old")
    }
    

    调用

    let zhangzong = Worker(name:"老张", age: 45)
    print(zhangzong)
    showWorker(worker: zhangzong)
    

    调用结果

    Worker(name: "老张", age: 45)
    老张 is 45 years old
    

    检验协议的一致性

    使用isas操作符检查是否遵循某协议或强制转化为某一协议类型

    protocol HasArea {
        var area:Double{get}
    }
    //圆
    class Circular:HasArea {
        let pi = 3.14159265
        var radius:Double
        var area: Double {
            return pi * radius * radius
        }
        init(radius:Double){
            self.radius = radius
        }
    }
    
    
    class Rectangular:HasArea {
        var width:Double
        var height:Double
        
        var area: Double{
            return width * height
        }
        
        init(width:Double,height:Double){
            self.width = width
            self.height = height
        }
    }
    
    class Hous{
        var rooms:Int = 0
        func configure(config: (Hous) -> Void) -> Hous {
            config(self)
            return self
        }
        
        func rooms(_ value: Int) -> Self {
            
            self.rooms = value
            return self
        }
    }
    

    调用

    let hous = Hous().configure{ $0.rooms = 3 }
            print(hous.rooms)
            
            
            let objs:[AnyObject] = [Circular(radius: 2.4),
                                    Rectangular(width: 5, height: 3),
                                    Hous().rooms(3),
                                    Hous().configure(config: {hous in
                hous.rooms = 5
            })]
            
            for obj in objs {
                if let objItem = obj as? HasArea{
                    print("面积为:\(objItem.area)")
                }else {
                    print("没有面积概念")
                }
            }
            
            
            let pro = Hous().rooms(3)
            if pro is HasArea{
                //print("矩形的面积:\(pro.area)")
            }else {
                print("有\(pro.rooms)个房间")
            }
    

    调用结果

    3
    面积为:18.095573664
    面积为:15.0
    没有面积概念
    没有面积概念
    有3个房间
    

    \color{gray}{欢迎大佬儿来指正纠错,共同学习😏!!}

    相关文章

      网友评论

        本文标题:iOS开发 - 「Swift 学习」Swift协议

        本文链接:https://www.haomeiwen.com/subject/iwhssrtx.html