Swift中的类和结构体(1)

类和结构体的比较

swift中的类:

class LLPerson {
    var age: Int
    var name: String
    
    init(_ age: Int, _ name: String) {
        self.age = age
        self.name = name
    }
}

var person = LLPerson(18, "LL")
var person1 = person


类是引用类型,personperson1是指针的赋值,指针指向的内容是一致的。

po : ppo 的区别在于使用 po 只会输出对应的值,而 p 则会返回值的类型以及命令结果的引用名。
x/8g: 读取内存中的值(8g: 8字节格式输出)

在这里插入图片描述
打印personperson1的地址是不一致的,存储的内存地址8字节。
在这里插入图片描述
创建person对象时,在栈区(stack)分配8字节,然后在堆区(heap)寻找位置分配空间,将值放到堆区,指针赋值给person,指针指向的是heap。可以使用cat address xxx查看指向。

swift中的结构体:

struct LLPerson {
    var age: Int
    var name: String
    
    init(_ age: Int, _ name: String) {
        self.age = age
        self.name = name
    }
}

var person = LLPerson(18, "LL")
var person1 = person

person1.age = 19
person1.name = "GG"

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
结构体是值类型,po打印出来的值,修改person1中的值,不会影响person

对于类,需要通过指针去heap中查找值,结构体只需要在stack上移动指针就可以。

结构体和类的主要相同点:

  1. 定义存储值的属性
  2. 定义方法
  3. 定义下标以使用下标语法提供对其值的访问
  4. 定义初始化器
  5. 使用 extension 来拓展功能
  6. 遵循协议来提供某种功能

主要不同点:

  1. 类有继承的特性,而结构体没有
  2. 类型转换使您能够在运行时检查和解释类实例的类型
  3. 类有析构函数用来释放其分配的资源
  4. 引用计数允许对一个类实例有多个引用

可以通过githubStructVsClassPerformance这个案例来直观的测试当前结构体和类的时间分配。

类的初始化器

在这里插入图片描述
在这里插入图片描述
当前的类编译器默认不会自动提供成员初始化器,但是对于结构体来说编译器会提供默认的初始化方法(前提是我们自己没有指定初始化器)!

class LLPerson {
    var age: Int
    var name: String
    
    init(_ age: Int, _ name: String) {
        self.age = age
        self.name = name
    }

    convenience init() {
        self.init(18, "LL")
    }
}

Swift中创建类和结构体的实例时必须为所有的存储属性设置一个合适的初始值。所以类LLPerson必须要提供对应的指定初始化器,同时我们也可以为当前的类提供便捷初始化器(convenience)(注意:便捷初始化器必须从相同的类里调用另一个初始化器)。
在这里插入图片描述
便携初始化器必须先调用其他初始化器,否则会编译不通过报错。必须在访问属性时,初始化属性。为了安全考虑。

初始化器规则:

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

可失败初始化器:

class LLPerson {
    var age: Int
    var name: String
    
    init?(_ age: Int, _ name: String) {
        if age < 18 {return nil}  
        self.age = age
        self.name = name
    }
    
    convenience init?(_ age: Int) {
        self.init(18, "LL")
    }
}

这种 Swift 中可失败初始化器写 return nil 语句,来表明可失败初始化器在何种情况下会触发初始化失败。

必要初始化器:
在这里插入图片描述
在类的初始化器前添加 required 修饰符来表明所有该类的子类都必须实现该初始化器。

类的生命周期

Swift 则是通过 Swift 编译器编译成 IR,然后在生成可执行文件。
在这里插入图片描述

分析输出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

可以通过swiftc -emit-sil ${SRCROOT}/LLSwiftTest/main.swift > ./main.sil & open main.sil 生成sil文件:

class LLPerson {
    var age: Int = 18
    var name: String = "LL"
}
class LLPerson {
  @_hasStorage @_hasInitialValue var age: Int { get set }
  @_hasStorage @_hasInitialValue var name: String { get set }
  @objc deinit
  init()
}

SLL文件可以参考https://github.com/apple/swift/blob/main/docs/SLL.rst
Swift 对象内存分配:

__allocating_init -----> swift_allocObject -----> swift_allocObject -----> swift_slowAlloc -----> Malloc

Swift 对象的内存结构 HeapObject (OC objc_object) ,有两个属性: 一个是Metadata ,一个是 RefCount ,默认占用 16 字节大小。
经过访问源码可得出以下结构:

类结构:

struct HeapObject { //自定义类结构
    var metaData: UnsafeRawPointer
    var refcounted1: UInt32
    var refcounted2: UInt32
}

class LLPerson {
    var age: Int = 18
    var name: String = "LL"
}

var person = LLPerson()

let objcRawPtr = Unmanaged.passUnretained(person as AnyObject).toOpaque() //获取对象指针
let objcPtr = objcRawPtr.bindMemory(to: HeapObject.self, capacity: 1)  //重新绑定
print(objcPtr.pointee)

在这里插入图片描述

metadata结构:

struct Metadata {  //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
}
let metadata = objcPtr.pointee.metaData.bindMemory(to: Metadata.self, capacity: MemoryLayout<Metadata>.stride).pointee
print(metadata)

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值