枚举为一组相关值定义了一个通用类型,从而可以让你在代码中类型安全地操作这些值。
你可以用 enum关键字来定义一个枚举,然后将其所有的定义内容放在一个大括号( {}
)中:
enum CompassPoint {
case north
case south
case east
case west
}
多个成员值可以出现在同一行中,要用逗号隔开:
enum CompassPoint {
case north,south,east,west
}
遍历枚举情况
对于某些枚举来说,如果能有一个集合包含了枚举的所有情况就好了。你可以通过在枚举名字后面写 : CaseIterable
来允许枚举被遍历。Swift 会暴露一个包含对应枚举类型所有情况的集合名为allCases
enum CompassPoint: CaseIterable {
case north
case south
case east
case west
}
for item in CompassPoint.allCases{
print(item)
}
print(CompassPoint.allCases.count)
//打印结果
north
south
east
west
4
关联值
枚举的成员值跟其他类型的值关联存储在一起
enum Date {
case digit(year:Int,month:Int,day:Int)
case dateString(String)
}
let date:Date = .digit(year: 2019, month: 10, day: 20)
原始值
枚举成员可以是哟哦那个相同类型的默认值预先对应,这个默认值叫:原始值
enum Score:String {
case perfect = "A"
case great = "b"
case goods = "c"
case bad = "d"
}
打印原始值 rawValue
print(Score.perfect.rawValue)
A
隐式原始值
当你在操作存储整数或字符串原始值枚举的时候,你不必显式地给每一个成员都分配一个原始值。当你没有分配时,Swift 将会自动为你分配值。
实际上,当整数值被用于作为原始值时,每成员的隐式值都比前一个大一。如果第一个成员没有值,那么它的值是 0 。
enum Score:String {
case perfect
case great
case goods
case bad
}
print(Score.perfect.rawValue)
perfect
在Int类型中,会默认从0开始
enum Season: Int{
case spring
case summer
case autumn
case winter
}
print(Season.spring.rawValue)
0
嵌套枚举
enum Area {
enum DongGuan {
case NanCheng
case DongCheng
}
enum GuangZhou {
case TianHe
case CheBei
}
}
print(Area.DongGuan.DongCheng)
方法
enum Device {
case iPad, iPhone, AppleTV, AppleWatch
func introduced() -> String {
switch self {
case .iPad: return "iPad"
case .iPhone: return "iPhone"
case .AppleWatch: return "AppleWatch"
case .AppleTV: return "AppleTV"
}
}
}
print(Device.iPhone.introduced())
iPhone
扩展
枚举也可以进行扩展。最明显的用例就是将枚举的case和method分离,这样阅读你的代码能够简单快速地消化掉enum内容,紧接着转移到方法定义:
enum Device {
case iPad, iPhone, AppleTV, AppleWatch
}
extension Device: CustomStringConvertible{
func introduced() -> String {
switch self {
case .iPad: return "iPad"
case .iPhone: return "iPhone"
case .AppleWatch: return "AppleWatch"
case .AppleTV: return "AppleTV"
}
}
var description: String {
switch self {
case .iPad: return "iPad"
case .iPhone: return "iPhone"
case .AppleWatch: return "AppleWatch"
case .AppleTV: return "AppleTV"
}
}
}
print(Device.AppleTV.description)
print(Device.iPhone.introduced())
MemoryLayout
可以使用MemoryLayout
获取类型所占用的内存大小
enum Season{
case num(Int,Int,Int,Int)
case winter
}
print(MemoryLayout<Season>.stride) //40 分配占用的空间大小
print(MemoryLayout<Season>.size) //33 实际用到的空间大小
print(MemoryLayout<Season>.alignment)//8 对其参数
枚举底层分析
我们来查看一下枚举所占内存
enum TestEnum {
case test1
case test2
case test3
case test4
case test5
}
print(MemoryLayout<TestEnum>.stride) 1
print(MemoryLayout<TestEnum>.size) 1
print(MemoryLayout<TestEnum>.alignment) 1
这样的枚举所占内存为1个字节
如果我们把test1=1000
呢
enum TestEnum :Int{
case test1 = 1000
case test2
case test3
case test4
case test5
}
print(MemoryLayout<TestEnum>.stride) //1
print(MemoryLayout<TestEnum>.size) //1
print(MemoryLayout<TestEnum>.alignment) //1
然后打印还是1个字节
。其实如果不设置关联值,枚举的大小就是一个字节。
我们来查看一下内存布局,这里需要借助一下一个小工具,具体下载地址
- 1、先打印出
a
的内存地址:Mems.ptr(ofVal: &a)
- 2、打断点->右击->
view Memory of a
- 3、输入打印出来的内存地址
我们在按照上面步骤研究一下更复杂的枚举
enum TestEnum {
case test1(Int,Int,Int)
case test2(Int,Int)
case test3(Int)
case test4(Bool)
case test5
}
print(MemoryLayout<TestEnum>.stride) //32
print(MemoryLayout<TestEnum>.size) //25
print(MemoryLayout<TestEnum>.alignment) //8
/*
64 00 00 00 00 00 00 00
01 00 00 00 00 00 00 00
02 00 00 00 00 00 00 00
00
00 00 00 00 00 00 00
*/
var a = TestEnum.test1(100,2,3)
print(Mems.ptr(ofVal: &a))
/*
64 00 00 00 00 00 00 00
01 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
01
00 00 00 00 00 00 00 00 00
*/
a = .test2(100, 1)
/*
64 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
02
00 00 00 00 00 00 00
*/
a = .test3(100)
总结
- 1、枚举中有一个字节存储成员值
- 2、N个字节存储关联值(N取最大关联值),任何一个case的关联值都公用这N个字节
网友评论