iOS开发-Swift进阶之枚举enum!

swift进阶总汇

本文主要介绍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是通过枚举值的rawValueget方法获取

  • 查看SIL文件rawValue的get方法,主要有以下几步:

    • 1、接收一个枚举值,用于匹配对应的分支

    • 2、在对应分支创建对应的String

    • 3、返回对应的String

结论1:使用rawValue的本质是调用get方法

但是get方法中的String是从哪里来的呢?String存储在哪里?

  • 其实这些对应分支的字符串在编译时期就已经存储好了,即存放在Maach-O文件的__TEXT.cstring中,且是连续的内存空间,可以通过编译后查看Mach-O文件来验证

结论2rawValueget方法中的分支构建的字符串,主要是从Mach-O文件对应地址取出的字符串,然后再返回给w

总结

  • 使用rawValue的本质就是在底层调用get方法,即在get方法中从Mach-O对应地址中取出字符串并返回的操作

区分 case枚举值 & rawValue原始值

请问下面这段代码的打印结果是什么?

//输出 case枚举值
print(Week.MON)
//输出 rawValue 
print(Week.MON.rawValue)

<!--打印结果-->
MON
MON

虽然这两个输出的值从结果来看是没有什么区别的,虽然输出的都是MON,但并不是同一个东西

  • 第一个输出的case枚举值

  • 第二个是通过rawValue访问的rawValueget方法

如果我们像下面这种写法,编译器就会报错

枚举的init调用时机

主要是探索枚举的init会在什么时候调用

  • 定义一个符号断点Week.init

  • 定义如下代码

print(Week.MON.rawValue)

let w = Week.MON.rawValue

通过运行结果发现,都是不会走init方法的

  • 如果是通过init方式创建enum呢?
print(Week.init(rawValue: "MON"))

运行结果如下

注:这个断

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值