美文网首页
swift-- 协议

swift-- 协议

作者: Mjs | 来源:发表于2020-12-28 17:32 被阅读0次

    协议的基本⽤法

    协议的语法格式

    protocol MyProtocol{ 
     //body 
     }
    

    我们熟悉的 class , struct , enum 都可以遵循协议,如果要遵守多个协议,使⽤逗号分隔。

    struct Teacher: Protocol1, Protocol2{ 
    //body 
     }
    

    这⾥特别说⼀下,如果 class 中有 superClass ,⼀般我们放在遵循的协议之前

    class Teacher: NSObject, Protocol1{ 
     //body 
    }
    

    协议中可以添加属性,⽤⼏个点需要注意⼀下:

    • 协议同时要求⼀个属性必须明确是可读的或可读的和可写的
    • 属性要求定义为变量属性
    protocol MyProtocol{
        var age:Int {get}
        var time:Int{get set}
    }
    class myClass: MyProtocol {
        var time: Int = 0
        var age: Int {
            get{
                time * time
            }
        }
    }
    

    在协议中定义⽅法,我们只需要定义当前⽅法的名称,参数列表和返回值

    protocol MyProtocol{
        func doSomething()
        //可能被结构体或者类继承 
        static func teach()
    }
    class myClass: MyProtocol {
        func doSomething() {
            print("doSomething")
        }
        
        static func teach() {
            print("teach")
        }
    }
    

    协议中也可以定义初始化⽅法,当我们实现初始化器的时候,必须使⽤ required 关键字

    protocol MyProtocol{
        init(age:Int)
    }
    class myClass: MyProtocol {
        required init(age: Int) {
            print(age)
        }
    }
    

    如果想要协议只能被类准守,需要实现AnyObject

    protocol MyProtocol:AnyObject
    

    将协议作为类型

    • 作为函数,⽅法或初始化程序中的参数类型或返回类型
    • 作为常量,变量或属性的类型
    • 作为数组,字典或其他容器中项⽬的类型
    protocol MyProtocol {
        func teach()
    }
    extension MyProtocol {
        func teach() { print("MyProtocol") }
    }
    class Teacher: MyProtocol {
        func teach() { print("MyClass") }
    }
    let object: MyProtocol = Teacher()
    object.teach()
    let object1: Teacher = Teacher()
    object1.teach()
    ···············
    MyClass
    MyClass
    

    通过sil文件可以看到

      %10 = witness_method $@opened("5DA67B08-48DE-11EB-AA97-ACDE48001122") MyProtocol, #MyProtocol.teach!1 : <Self where Self : MyProtocol> (Self) -> () -> (), %9 : $*@opened("5DA67B08-48DE-11EB-AA97-ACDE48001122") MyProtocol : $@convention(witness_method: MyProtocol) <τ_0_0 where τ_0_0 : MyProtocol> (@in_guaranteed τ_0_0) -> () // type-defs: %9; user: %11
      %11 = apply %10<@opened("5DA67B08-48DE-11EB-AA97-ACDE48001122") MyProtocol>(%9) : $@convention(witness_method: MyProtocol) <τ_0_0 where τ_0_0 : MyProtocol> (@in_guaranteed τ_0_0) -> () // type-defs: %9
    
    
    // protocol witness for MyProtocol.teach() in conformance Teacher
    sil private [transparent] [thunk] @$s4main7TeacherCAA10MyProtocolA2aDP5teachyyFTW : $@convention(witness_method: MyProtocol) (@in_guaranteed Teacher) -> () {
    // %0                                             // user: %1
    bb0(%0 : $*Teacher):
      %1 = load %0 : $*Teacher                        // users: %2, %3
      %2 = class_method %1 : $Teacher, #Teacher.teach!1 : (Teacher) -> () -> (), $@convention(method) (@guaranteed Teacher) -> () // user: %3
      %3 = apply %2(%1) : $@convention(method) (@guaranteed Teacher) -> ()
      %4 = tuple ()                                   // user: %5
      return %4 : $()                                 // id: %5
    } // end sil function '$s4main7TeacherCAA10MyProtocolA2aDP5teachyyFTW'
    
    sil_vtable Teacher {
      #Teacher.teach!1: (Teacher) -> () -> () : @$s4main7TeacherC5teachyyF  // Teacher.teach()
      #Teacher.init!allocator.1: (Teacher.Type) -> () -> Teacher : @$s4main7TeacherCACycfC  // Teacher.__allocating_init()
      #Teacher.deinit!deallocator.1: @$s4main7TeacherCfD    // Teacher.__deallocating_deinit
    }
    
    sil_witness_table hidden Teacher: MyProtocol module main {
      method #MyProtocol.teach!1: <Self where Self : MyProtocol> (Self) -> () -> () : @$s4main7TeacherCAA10MyProtocolA2aDP5teachyyFTW   // protocol witness for MyProtocol.teach() in conformance Teacher
    }
    

    witness_method : 通过PWT (协议⽬击表)获取对应的函数地址.
    在main函数中通过witness_table调用继承协议的实现找到vtable
    如果把协议中的声明去掉

    protocol MyProtocol {
        //func teach()
    }
    extension MyProtocol {
        func teach() { print("MyProtocol") }
    }
    class Teacher: MyProtocol {
        func teach() { print("MyClass") }
    }
    let object: MyProtocol = Teacher()
    object.teach()
    let object1: Teacher = Teacher()
    object1.teach()
    ···············
    MyProtocol
    MyClass
    

    再次查看sil

     // function_ref MyProtocol.teach()
      %10 = function_ref @$s4main10MyProtocolPAAE5teachyyF : $@convention(method) <τ_0_0 where τ_0_0 : MyProtocol> (@in_guaranteed τ_0_0) -> () // user: %11
      %11 = apply %10<@opened("E3E7015A-48DF-11EB-8960-ACDE48001122") MyProtocol>(%9) : $@convention(method) <τ_0_0 where τ_0_0 : MyProtocol> (@in_guaranteed τ_0_0) -> () // type-defs: %9
    

    直接调用了协议里的方法

    PWT到底存放在哪里呢

    protocol Shape{
     var area: Double{ get }
    }
    class Circle: Shape{
        var radious: Double
        init(_ radious: Double) {
            self.radious = radious
        }
        var area: Double{
            get{
                return radious * radious * 3.14
            }
        }
    }
    var circle:Shape = Circle.init(10.0)
    

    swiftc -emit-ir main.swift | xcrun swift-demangle > ./main.ll && open main.ll

    //操作的都是这个结构体
    %T4main5ShapeP = type { [24 x i8], %swift.type*, i8** }
    
    //将metadata放入
      store %swift.type* %4, %swift.type** getelementptr inbounds (%T4main5ShapeP, %T4main5ShapeP* @"main.circle : main.Shape", i32 0, i32 1), align 8
    //将pwt放入
      store i8** getelementptr inbounds ([2 x i8*], [2 x i8*]* @"protocol witness table for main.Circle : main.Shape in main", i32 0, i32 0), i8*** getelementptr inbounds (%T4main5ShapeP, %T4main5ShapeP* @"main.circle : main.Shape", i32 0, i32 2), align 8
    //将heapObject放入
      store %T4main6CircleC* %5, %T4main6CircleC** bitcast (%T4main5ShapeP* @"main.circle : main.Shape" to %T4main6CircleC**), align 8
    

    用swift来模拟一下

    protocol Shape{
     var area: Double{ get }
    }
    struct Circle: Shape{
        var radious: Double
        var radious1: Double = 20
        var radious2: Double = 30
    //    var radious3: Double = 40
        init(_ radious: Double) {
            self.radious = radious
        }
        var area: Double{
            get{
                return radious * radious * 3.14
            }
        }
    }
    
    var circle:Shape = Circle.init(10.0)
    //24字节
    struct  protocolData {
        var value1:UnsafeRawPointer
        var value2:UnsafeRawPointer
        var value3:UnsafeRawPointer
        var type:UnsafeRawPointer
        var pwt:UnsafeRawPointer
    }
    
    withUnsafePointer(to: &circle, { ptr in
        ptr.withMemoryRebound(to: protocolData.self, capacity: 1, {point in
            print(point.pointee)
        })
    })
    ·················
    protocolData(value1: 0x4024000000000000, value2: 0x4034000000000000, value3: 0x403e000000000000, type: 0x0000000100003098, pwt: 0x0000000100003028)
    

    通过实现可以发现如果我们在结构体Circle声明三个变量,就会分配存放在value1value2value3中,也就是valuebuffer中,超过3个属性,就会在value中开辟一个内存空间进行存放

    相关文章

      网友评论

          本文标题:swift-- 协议

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