Swift进阶:一、Swift类与结构体

378 阅读5分钟

1、初识类与结构体

什么时候用类? 什么时候用结构体?

答案其实很简单:当你需要值语义(值语义是指一个对象被系统标准的复制方式复制之后,与被复制的对象之间毫无关系,彼此独立改变且互不影响)的时候使用结构体,当你需要引用语义(引用语义是指一个对象被系统标准的复制方式复制后,与被复制的对象之间依然共享底层资源,对其中一个的改变都将影响到另外一个)的时候使用类。

struct/class LGTeacher{
    var age: Int
    var name: String

    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
    
    //只有类有构析函数,结构体没有
    deinit{

    }
}

1.1、类和结构体的相同点

  • 定义属性用于存储值

  • 定义方法用于提供功能

  • 定义下标操作用于通过下标语法访问它们的值

  • 定义构造器用于设置初始值

  • 通过扩展以增加默认实现之外的功能

  • 遵循协议以提供某种标准功能

1.2、类和结构体的不同点

  • 继承允许一个类继承另一个类的特征

  • 类型转换允许在运行时检查和解释一个类实例的类型

  • 析构器允许一个类实例释放任何其所被分配的资源

  • 引用计数允许对一个类的多次引用

1.3、 值类型与引用类型

值类型引用类型
变量中存储的是地址变量中存储的是具体的实例(具体的值)
值类型存储的在栈上引用类型存储在堆上

引用类型: image.png

值类型: image.png

1.4、内存分布

待写

2、类的构造器

2.1、结构体类型的成员逐一构造器

所有结构体都有一个自动生成的成员逐一构造器,用于初始化新结构体实例中成员的属性。新实例中各个属性的初始值可以通过属性的名称传递到成员逐一构造器之中:

let vga = Resolution(width: 640, height: 480)

与结构体不同,类实例没有默认的成员逐一构造器。

我们可以通过构造器来给属性赋值。使用 init 来定义构造器,语法如下:

// 注意这里没有使用func来修饰
init(parameter: SomeType) {
  // 初始化代码
}

2.2、指定构造器和便利构造器

Swift 为类的构造过程提供了两种构造器,分别是指定(designated)构造器和便利(convenience)构造器。Swift 通过便利构造器给一些属性赋默认值,从而达到简化参数传递个数的目的。这两种构造器有几个使用原则:

  • 指定初始化器必须保证在向上委托给父类初始化器之前,其所在类引入的所有属性都要初始化完成。
  • 指定初始化器必须先向上委托父类初始化器,然后才能为继承的属性设置新值。如果不这样做,指定初始化器赋予的新值将被父类中的初始化器所覆盖
  • 便捷初始化器必须先委托同类中的其它初始化器,然后再为任意属性赋新值(包括同类里定义的属性)。如果没这么做,便捷构初始化器赋予的新值将被自己类中其它指定初始化器所覆盖。
  • 初始化器在第一阶段初始化完成之前,不能调用任何实例方法、不能读取任何实例属性的值,也不能引用 self 作为值。
  • 一个便利构造器最终一定会调用一个指定构造器

2.3、可失败构造器

当前因为参数的不合法或者外部条件 的不满足,存在初始化失败的情况。这种 Swift 中可失败初始化器写 return nil 语句,来表明可失败初始化器在何种情况下会触发初始化失败

image.png

2.4、必要构造器

在类的构造器前添加 required 修饰符来表明所有该类的子类都必须实现该构造器

image.png

3、类的生命周期

3.1 编译

iOS开发的语言不管是OC还是Swift后端都是通过LLVM进行编译的,如下图所示: image.png

OC 通过 clang 编译器,编译成 IR,然后再生成可执行文件 .o(这里也就是我们的机器码) Swift 则是通过 Swift 编译器编译成 IR,然后在生成可执行文件。

image.png

操作步骤:

// 分析输出AST
swiftc main.swift -dump-parse

// 分析并且检查类型输出AST
swiftc main.swift -dump-ast

// 生成中间体语言(SIL),未优化
swiftc main.swift -emit-silgen

// 生成中间体语言(SIL),优化后的
swiftc main.swift -emit-sil

// 生成LLVM中间体语言 (.ll文件)
swiftc main.swift -emit-ir 

// 生成LLVM中间体语言 (.bc文件)
swiftc main.swift -emit-bc 

// 生成汇编
swiftc main.swift -emit-assembly 

// 编译生成可执行.out文件
swiftc -o main.o main.swift

3.2 对象内存分配

Swift 对象内存分配:

  1. __allocating_init -----> swift_allocObject -----> swift_allocObject -----> swift_slowAlloc -----> Malloc
  2. Swift 对象的内存结构 HeapObject (OC objc_object) ,默认占用 16 字节大小,有两个属性:
    • Metadata, 8个字节大小
    • RefCount,8个字节大小

3.3 swift类的数据结构

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 
}