Swift 类与结构体(下)

持续创作,加速成长!这是我参与「掘金日新计划 · 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
}
复制代码

猜你喜欢

转载自juejin.im/post/7111552959142363166