美文网首页
swift 协议

swift 协议

作者: 皆为序幕_ | 来源:发表于2019-05-23 17:09 被阅读0次

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

    协议语法

    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
    

    代理模式

    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()
    

    通过分类为现有类型添加属性、方法等等

    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")
        }
    }
    

    协议的继承

    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()
    }
    

    相关文章

      网友评论

          本文标题:swift 协议

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