持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第20天,点击查看活动详情
异变方法
上一节我们了解到,Swift 中 class 和 struct 都能定义方法。但是有一点区别的是默认情况 下,值类型属性不能被自身的实例方法修改。
struct Point {
var x = 0.0,
y = 0.0
func moveBy(x deltaX: Double, y deltaY: Double) {
//self
x += deltaX
y += deltaY
}
}
复制代码
通过 SIL 来对比一下,不添加 mutating 访问和添加 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
}
}
复制代码
sil hidden [ossa] @$s4main5PointV4testyyF : $@convention(method) (Point) ->
debug_value %0 : $Point, let, name "self", argno 1 // id: %1
复制代码
sil hidden [ossa] @$s4main5PointV6moveBy1x1yySd_SdtF : $@convention(method)
@inout Point
debug_value_addr %2 : $*Point, var, name "self", argno 3 // id: %5
let self = Point
var self = &Point
复制代码
SIL 文档的解释
An @inout parameter is indirect. The address must be of an initialized object.(当前参数 类型是间接的,传递的是已经初始化过的地址)
异变方法的本质:对于变异方法, 传入的 self 被标记为 inout 参数。无论在 mutating 方法 内部发生什么,都会影响外部依赖类型的一切。
输入输出参数:如果我们想函数能够修改一个形式参数的值,而且希望这些改变在函数结束之后 依然生效,那么就需要将形式参数定义为 输入输出形式参数 。在形式参数定义开始的时候在前边 添加一个 inout关键字可以定义一个输入输出形式参数
方法调度
objc_mgsend
我们先来看一下 Swift 中的方法调度
class LGTeacher{
func teach(){
print("teach")
}
}
var t = LGTeacher()
t.teach()
复制代码
teach函数的调用过程:找到 Metadata 基于函数表的调度,确定函数地址(metadata + 偏移量), 执行函数之前我们在第一节课讲到了 Metdata 的数据结构,那么 V-Table 是存放在什么地方那? 我们先来回顾一下当前的数据结构
struct Metadata{
var kind: Int
var superClass: Any.Type
var cacheData: (Int, Int)
var data: Int var classFlags: Int32
var instanceAddressPoint: UInt32
var instanceSize: UInt32
var instanceAlignmentMask: UInt16
var reserved: UInt16
var classSize: UInt32
var classAddressPoint: UInt32
var typeDescriptor: UnsafeMutableRawPointer
var iVarDestroyer: UnsafeRawPointer
}
复制代码
这里我们有一个东⻄需要关注 typeDescriptor ,不管是 Class , Struct , Enum 都有自己 的 Descriptor ,就是对类的一个详细描述
struct TargetClassDescriptor{
var flags: UInt32
var parent: UInt32
var name: Int32
var accessFunctionPointer: Int32
var fieldDescriptor: Int32
var superClassType: Int32
var metadataNegativeSizeInWords: UInt32
var metadataPositiveSizeInWords: UInt32
var numImmediateMembers: UInt32
var numFields: UInt32
var fieldOffsetVectorOffset: UInt32 var Offset: UInt32
var size: UInt32
//V-Table
}
复制代码