1、初识类与结构体
Swift 中类用class修饰,结构体用struct修饰
class ClassSwagger{
var age:Int
var name:String
init(age:Int, name:String) {
self.age = age
self.name = name
}
deinit{
}
}
struct StructSwagger{
var age:Int
var name:String
init(age:Int, name:String) {
self.age = age
self.name = name
}
}
1.1 结构体和类的相同点不同点
相同点
- 定义存储值的属性
- 定义方法
- 定义下标以使用下标语法提供对其值的访问
- 定义初始化器
- 可以使用 extension 来拓展功能
- 遵循协议来提供某种功能
主要的不同点
- 类有继承的特性,而结构体没有
- 类型转换使您能够在运行时检查和解释类实例的类指针是什么型
- 类有析源码交易网站源码构函数用来释放其分配的资源
- 引用计数允许对一个类指针式万用表实例有多个引用后端开发工程师
1.2 类和源码网站结构体最本质的swift全称区别
类是引用类型,结构体是指类型
我后端们可以通后端框架过lld指针数组和数组指针的区别b 指令来查看当前变量的内存结构
po:只会输出对应的值
p:swift翻译返回值的类型以及命令结果 的引用名
x/8g:读取内存中的值(8后端框架g: 8字节格式输出)
frame variable -L 打印对象的内存布局
- 类类型的引用
一个类类型的变量并不直接存储具体的实例对象,是对当前存储具体实例内存地址的引用,如图所示
s 和 s1 的地址是相同的,且两个变量引用对源码时代象的内存地址完全相同符合引用类型的结果。
- 结构体是值类型
结构体是一种值类型,内存分配在栈中。复制后新的实例swift代码和值类型成员属性的地址空间都是重新分配的,引用类型的成员属性仍指针万用表怎么读数然指指针是什么向之前的地址空间
ct 和 ct1 的地址是不相同的,且每个变量的内存地址中存储的属性也是不同的地址,说明两个指向的是两个实例对象
存储区域的不同
引用类型和值类型还有一个最直观的区别就是存储的位置不同: 一般情况,值类型存储的在栈上,引用类型存储在堆上
- 对于类的内存分配
- 在栈上开辟 8 字节内存空间存储 s 变量,s1 变量中存储 ClassSwagger 的地址
- 在堆上,会寻找合适的内存区域,开辟内存,存储 ClassSwagger 的实例对象
- 函数结束时,会销毁栈上的指针swift翻译,查找并回收堆上的示例变量
- 对于结构体的内存分配
- 在栈上直接分配结构体内存大小的空间存储结构体的值
2、初始化器
初始化器是为了可以完整地初始化实例,所以在初始化器中必须完成对存储属性的赋值
2.1 默认初始化器
- 编译器不会自动提供类的初始化器,需要自己提供一个指定初始化器
- 结构体来说编译器会提供默认的初始化方法(前提是我们自己没有指定初始化器)!
2.2 指定初始化器
- 每个类至少有一个指定初始化器,指定初始化器是类的主要初始化器,类偏向于少量指定初始化器,一个类通常只有一个指定初始化成员变量有默认值吗器
- 指定初始化器必须保证在向上委托给父类初始化器之前,其所在源码编辑器类引入的所有属性都要初始化完成
- 指定初始化器必须先向上委托父类初始化器,然后才能为继承的属性设置新值
2.3 类的便利初始化器
便捷初始化器必须先委托同类中的其它初始化器,然后再成员变量和局部变量区别为任意属性赋新值(包括 同类里定义的属性)
2.4 可失败初始化器
当前因为参数的不合法或者外部条件的不满足,存在初始化失败的情况

2.5 必要swift组织初始化器
在类的初始化器前添加 required 修饰符来表明所有该类的子类都必须实现该初始化器


3、类的生命周期
3.1 Swift的编译
iOS开发的语言不管是OC还是Swift后端都是通过LLVM进行编译的,如下图所示:
- OC 通过clang编译器,编译成IR,然后再生成可执行源码1688文件 .o(这里也就是我们的机器码)
- Swift则是通过Swift编译器编译成IR,然后在生成可执行文件
3.2 Swift后端语言源码分析
Swift源码
搜索HeapObject.cpp文件找到swift_allocObject函数可以看到内部调用了swift_slowAlloc函数

swiftSwift_slowAlloc函后端语言数可以看到调用了m源码alloc

__allocating_init->swift_allocObject->_swift_allocObject_–成员变量和成员方法>swift_slowAlloc->malloc
Swift对象源码编辑器的内存结构Heapswift代码Object(OC objc_object) 有两个属性: 一成员变量和局部变量区别个是Metadata,一个是RefCount,默认占用16字节大小
4、类的结构成员变量和成员方法窥探
在OC 中类的只有后端开发是干什么的一个isa指针,但是在 swift 中有HeapMetadata和refCounts两个属性
4.1 Metadata源码分析
Metadata的继承关系及结构简述
查看Metadata的源码可以看到Metadata是HeapMetadata类型这是TargetHeapMetad指针万用表的使用方法ata定义的别成员变量和局部变量区别名

查看TargetHeapMetadata可得它继承自TargetMetadata,同时也可以知道 其初始化时如指针c语言果是 纯swift类则传入MetadataKind kind如果是和 OC 交互的类传入isa

在TargetMetadata中可得到一个 kind 的成员变量

MetadataKind 的解析
查看MetadataKind可得它是一个 uint32_t的类型

MetadataKind有如下类型

4.2 类的结构分析
源码分析猜想
上面说到了 Metadata 最终继承自TargetMetadata,且其成员中的 kind 对应多种类型,所以猜测 Met源码1688adata 最终会源码时代在这里完成创建 通过源码分析可以看到下面的这个函数

TargetMetadata转换为其他类型的 Meswift翻译tadata ,所以TargetMetadata指针和引用的区别可能就是所有类型的元类型的基类
当 kind 的后端开发是干什么的 是Class 时会将 this 强转为TargetClswiftlyassMetadata类型 这个类型可能就是类swift是什么的最终结构,所以分析它的结构就应该可以得到类的大致结构
case MetadataKind::Class: {
const auto cls = static_cast<const TargetClassMetadata<Runtime> *>(this);
进入TargetClassMetad指针ata其继承自TargetAnyClassMetadata


TargetClass指针说漫Metadata : TargetAnyClassMetadata :TargetH后端框架ea成员变量pMetadata : TargetMetada源码交易网站源码ta
经过以上分析,可以大致得出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
}
强转结构验证
上面分析得到类的实例对象结构是HeapObject有两个属性: 一个是Metadata,一个是RefCount
所以我们自定义一个结构体,然后将我们的实例对象强转为该类型,如果转换成功则说明分析正确swift是什么意思啊
结果说明
- 上面分析的
类的实例对象结构为HeapObject类型 - metadata 可以转换成上述分析的
Metadata类型





















评论(0)