本文主要介绍enum的常见使用形式,以及枚举大小是如何计算的

补充:添加脚本自动生成SIL
- 通过target -> +,选择 other -> Aggregate,然后命名为
CJLScript


-
选中CJLScript,选择
Build Phases->New Run Script Phase
-
在
Run Script中输入以下命令
swiftc -emit-sil ${SRCROOT}/06、EnumTest/main.swift | xcrun swift-demangle > ./main.sil && code main.sil
然后我们就可以通过脚本自动生成SIL并自动打开啦 ✿✿ヽ(°▽°)ノ✿✿
C中的枚举
在介绍swift中的枚举之前,首先我们来回顾下C中的枚举写法,如下所示
enum 枚举名{
枚举值1,
枚举值2,
......
};
<!--举例:表示一周7天-->
enum Week{
MON, TUE, WED, THU, FRI, SAT, SUN
};
<!--更改C中枚举默认值-->
//如果没有设置枚举默认值,一般第一个枚举成员的默认值为整型0,后面依次递推
enum Week{
MON = 1, TUE, WED, THU, FRI, SAT, SUN
};
<!--C中定义一个枚举变量-->
//表明创建了一个枚举,并声明了一个枚举变量Week
enum Week{
MON = 1, TUE, WED, THU, FRI, SAT, SUN
}week;
//或者下面这种写法,省略枚举名称
enum{
MON = 1, TUE, WED, THU, FRI, SAT, SUN
}week;
Swift中的枚举
在swift中,枚举的创建方式如下所示,如果没有指定枚举值的类型,那么enum默认枚举值是整型的
<!--1、写法一-->
enum Week{
case MON
case TUE
case WED
case THU
case FRI
case SAT
case SUN
}
<!--2、写法二-->
//也可以直接一个case,然后使用逗号隔开
enum Week{
case MON, TUE, WED, THU, FRI, SAT, SUN
}
<!--定义一个枚举变量-->
var w: Week = .MON
- 如果此时想创建一个枚举值是String类型的enum,可以通过指定enum的枚举值的类型来创建,其中
枚举值和原始值rawValue的关系为case 枚举值 = rawValue原始值
/*
- =左边的值是枚举值,例如 MON
- =右边的值在swift中称为 RawValue(原始值),例如 "MON"
- 两者的关系为:case 枚举值 = rawValue原始值
*/
enum Week: String{
case MON = "MON"
case TUE = "TUE"
case WED = "WED"
case THU = "THU"
case FRI = "FRI"
case SAT = "SAT"
case SUN = "SUN"
}
- 如果不想写枚举值后的字符串,也可以使用
隐式RawValue分配,如下所示
<!--String类型-->
enum Week: String{
case MON, TUE, WED = "WED", THU, FRI, SAT, SUN
}
<!--Int类型-->
//MON是从0开始一次递推,而WED往后是从10开始一次递推
enum Week: Int{
case MON, TUE, WED = 10, THU, FRI, SAT, SUN
}
枚举的访问
作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS开发交流群:130 595 548,不管你是小白还是大牛都欢迎入驻 ,让我们一起进步,共同发展!(群内会免费提供一些群主收藏的免费学习书籍资料以及整理好的几百道面试题和答案文档!)
注:如果enum没有声明类型,是没有
rawValue属性的

枚举的访问方式如下所示
enum Week: String{
case MON, TUE, WED, THU, FRI, SAT, SUN
}
var w = Week.MON.rawValue
<!--访问-->
print(w)
<!--打印结果-->
MON
这里就有一个疑问,swift是如何做到打印 MON的?我们通过SIL文件分析
- 首先查看
SIL文件中的enum,底层多增加了一些东西-
1、给枚举值的类型,通过
typealias取了一个别名RawValue -
2、默认添加了一个
可选类型的init方法 -
3、增加一个
计算属性rawValue,用于获取枚举值的原始值
-

-
查看SIL中的
main方法,可以得知w是通过枚举值的rawValue的get方法获取
-
查看SIL文件
rawValue的get方法,主要有以下几步:-
1、接收一个枚举值,用于匹配对应的分支
-
2、在对应分支创建对应的String
-
3、返回对应的String
-

结论1:使用rawValue的本质是调用get方法
但是get方法中的String是从哪里来的呢?String存储在哪里?
- 其实这些对应分支的字符串在编译时期就已经存储好了,即存放在
Maach-O文件的__TEXT.cstring中,且是连续的内存空间,可以通过编译后查看Mach-O文件来验证

结论2:rawValue的get方法中的分支构建的字符串,主要是从Mach-O文件对应地址取出的字符串,然后再返回给w
总结
- 使用
rawValue的本质就是在底层调用get方法,即在get方法中从Mach-O对应地址中取出字符串并返回的操作
区分 case枚举值 & rawValue原始值
请问下面这段代码的打印结果是什么?
//输出 case枚举值
print(Week.MON)
//输出 rawValue
print(Week.MON.rawValue)
<!--打印结果-->
MON
MON
虽然这两个输出的值从结果来看是没有什么区别的,虽然输出的都是MON,但并不是同一个东西
-
第一个输出的
case枚举值 -
第二个是通过
rawValue访问的rawValue的get方法
如果我们像下面这种写法,编译器就会报错

枚举的init调用时机
主要是探索枚举的init会在什么时候调用
-
定义一个符号断点
Week.init
-
定义如下代码
print(Week.MON.rawValue)
let w = Week.MON.rawValue
通过运行结果发现,都是不会走init方法的
- 如果是通过
init方式创建enum呢?
print(Week.init(rawValue: "MON"))
运行结果如下

本文详细探讨了Swift中的枚举,包括C中的枚举对比、Swift枚举的创建、访问、枚举大小的计算、模式匹配、关联值、嵌套枚举以及内存对齐等。重点解析了Swift枚举的get方法原理,枚举的rawValue与case枚举值的区别,以及枚举在内存中的存储方式。同时,文章提供了多种枚举的使用示例,如具有关联值的枚举、枚举的遍历以及枚举在Swift与Objective-C混编中的应用。
最低0.47元/天 解锁文章
1115





