枚举介绍
- 隐式分配机制
前面是从0开始的,从FRI开始被指定从10开始,观察String类型的RawValue
- RawValue
查看SIL文件
从上图可知,是调用
getter方法,来获取枚举值的,查看getter方法返回构建好的字符串
构建字符串是在
编译的时候就已经构建好的,并且存放在Macho文件的__TEXT.cstring下面他的构建方法就是去到
__TEXT.cstring下面找到对应的地址, 把对应的字符串拿出来 - Raw和枚举值的区别
上图中
weak.MON.rawValue和weak.MON的输出是一样的,但并不代表他俩就是相同的,从下面赋值可看出weak.MON是无法赋值的rawValue是String类型的
而MON是weak类型的enum值
- enum初始化
分析enum是如何调用init的
图中init MON会打印一个可选值,但init PH却返回nil
查看sil文件
init是个可选的初始化方法,查看init
会先创建一个
数组,然后返回一个元祖,这个元祖中也包含一个数组(是元祖的第一个元素),还有一个指向元祖中这个数组的指针,通过指针的偏移会把macho中的枚举值连续的放入元祖的数组中
在把枚举值放完之后调用了一个
_findStringSwitchCase方法,在swift源码中查找返回到sil文件
如果没有相同的
- 关联值
通常用来表示复杂的定义
- 模式匹配
就是匹配所有的枚举值
- 关联值模式匹配
也可以通过if来进行匹配,意义和上面的switch是一样的
可以通过匹配来获得另一个枚举值中元祖关联值
不同的匹配值可改变x的值
- 枚举嵌套
允许组合的形式来进行嵌套!
结构体里面的枚举嵌套枚举中
包含属性,枚举中只能包含计算属性和类型属性,不能包含存储属性,因为在结构体中可以包含存储属性是结构体的大小就包含了存储属性的大小,而枚举的大小与case的个数相关
枚举包含方法
枚举大小
- 如果枚举中存在原始值(rawValue)
在内存中枚举就是以
一个字节的长度存储在内存当中,case默认是UInt8也就是1字节,不管有多少case,1字节最多存储256,如果超过了256,UInt8会自动升级成UInt16,如何还超过,继续往上升可看出在内存中是连续存储的
- 包含关联值的枚举
包含
有关联值的枚举大小取决于关联值的类型,关联值也是要取决于最大的那个case的关联值,上图上的rectangle的关联值比circle的大
上图中只是把case a的关联值类型更换后所占的内存就会发生变化
真实存储位:类型真是所占内存的大小叫真是存储位
补充位:当所占内存不足以字节对齐时,补充不足的位叫补充位
无效位:当一个enum中所占内存最大的case的补充位与其他case的补充位有相互重合的位时,这些相互重合的位,叫做无效位
enum tempA中
case a的关联值类型是Int占用8字节,不需要字节对齐,所以就没有补充位;
case b的关联值类型所占的实际内存是1,8,2,根据字节对齐需要把第1位后面补7位,那么占用的内存就是1+7,8,2;
因为要存储一个case类型,查看其他case 有没有和case b的补充位相重合的无效位,如果没有那就再加1位,也就是占了19位
enum tempB中
case a的关联值类型是Int8占用1字节,需要字节对齐,所以补充7位;
case b的关联值类型所占的实际内存是1,8,2,根据字节对齐需要把第1位后面补7位,那么占用的内存就是1+7,8,2;
因为要存储一个case类型,查看其他case 有没有和case b的补充位相重合的无效位,case b的补充位和case a的补充位有重合;
编译器为了优化节省内存把case类型存储到了case补充位的最后一位,所以占了18位