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可以看出,函数的地址空间是连续的,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()