Swift 类与结构体(下)

655 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第23天,点击查看活动详情


  1. Swift Optional
  2. Swift Enum
  3. iOS开发 做一个三角形
  4. Swfit 指针类型
  5. Swift 属性(下)
  6. Swift 属性
  7. Swift 小结
  8. Swift 类与结构体(下)
  9. Swift 类的生命周期
  10. Swift 类的初始化器
  11. Swift 类与结构体
  12. OpenGL 压缩纹理
  13. OpenGL 隧道坐标计算
  14. 0penGL 像素格式及数据类型
  15. OpenGL 纹理对象
  16. OpenGL 纹理
  17. OpenGL 模型变化
  18. OpenGL 视图
  19. OpenGL 矩阵
  20. OpenGL 向量
  21. OpenGL 颜色混合
  22. OpenGL 深度测试的潜在风险
  23. OpenGL 浅析深度测试
  24. OpenGL 浅析隐藏面消除
  25. OpenGL 图元连接方式
  26. 记WKWebView与HTML完成交互两三事
  27. OpenGL 渲染流程图解析
  28. OpenGL 控制你的正方形
  29. OpenGL 专业名词解释
  30. OpenGL 环境搭建 - MacOS

上一篇,我们探讨了类的生命周期的内容点,今天,我们一起来看一下 Swift 中 类与结构体的 下半节内容。

异变方法

上上一节我们了解到,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
}