[Swift拓展]2、结构体与类

1、关键字mutating

通过SIL对比一下添加mutating和不添加的两者区别

struct Point {
    var x = 0.0, y = 0.0
    func test(){
        let tmp = self.x
    }
    mutating func moveBy(x deltaX: Double, y deltaY: Double) { 
        x += deltaX
        y += deltaY
    }
}

Xcode配置执行脚本命令
swiftc -emit-sil ${SRCROOT}/LGSwiftTest/main.swift > ./main.sil
打开main.sil文件

// func test
sil hidden @$s4main5PointV4testyyF : $@convention(method) (Point) -> () 
debug_value %0 : $Point, let, name "self", argno 1, implicit // id: %1
// func moveBy
sil hidden @$s4main5PointV6moveBy1x1yySd_SdtF : $@convention(method) (Double, Double, @inout Point) -> () 

SIL 文档的解释
An @inout parameter is indirect. The address must be of an initialized object.(当前参数 类型是间接的,传递的是已经初始化过的地址)
总结:
异变方法的本质:对于变异方法, 传入的 self 被标记为 inout 参数。无论在 mutating 方法 内部发生什么,都会影响外部依赖类型的一切。
输入输出参数:如果我们想函数能够修改一个形式参数的值,而且希望这些改变在函数结束之后 依然生效,那么就需要将形式参数定义为 输入输出形式参数 。在形式参数定义开始的时候在前边 添加一个 inout关键字可以定义一个输入输出形式参数

2、函数调用

2.1、函数调用

1、函数的地址空间是连续的。
看一下如下函数调用

class LGTeacher{ //继承关系吗?没有
    //消息调度的机制 
    func teach(){
        print("teach")
    }
    func teach1(){
        print("teach1")
    }
    func teach2(){
        print("teach2")
    }
}
let t = LGTeacher()
t.teach()
t.teach1()
t.teach2()
汇编执行过程

si

从上述汇编和si可以看出,函数的地址空间是连续的,teach函数的调用过程:找到 Metadata 基于函数表的调度确定函数地址(metadata + 偏移量), 执行函数,函数存放的位置为vtable中。

2.2、@_dynamicReplacement 方法替换

class LGTeacher { 
    dynamic func teach(){
        print("teach")
    }
}
extension LGTeacher {
    @_dynamicReplacement(for: teach)
    func teach3() {
        print("tech3333")
    }
}

编译后的sil文件

// LGTeacher.teach3()
sil hidden [dynamic_replacement_for "$s14ViewController9LGTeacherC5teachyyF"] [ossa] @$s14ViewController9LGTeacherC6teach3yyF : $@convention(method) 

最终方法teach3()被替换为teach()

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容