Swift中的枚举非常强大,但也会有也有点复杂,在不清楚其相关细节时,用球来总是没有那么得心应手,此文主要以代码呈现的方式秒速了swift枚举的一些特性
1定义
enum Direction1 {
case up
case down
case left
case right
}
enum Direction2 {
case up, down, left, right
}
let d1 = Direction1.up
switch d1 {
case .up: print("d1 is up")
case .down: print("d1 is down")
default: print("d1 is none")
}
2.关联值
enum Date {
case digit(year: Int, month: Int, day: Int)
case string(String)
}
let d1 = Date.digit(year: 2019, month: 7, day: 10)
print(d1)
let d2 = Date.string("2019-7-10")
print(d2)
enum Password {
case number(Int, Int, Int, Int, Int, Int)
case string(String)
}
3.原始值
enum Grade: String {
case perfect = "A"
case great = "B"
case good = "C"
case bad
}
// 如果不给原始值,会自动取名字字符串
// 如果是字符类型Charater必须全部初始化
let g: Grade = .good // g = good、g.rawValue = C
print("g == \(g)")
print("g rawValue == \(g.rawValue)")
let g1: Grade = .bad // g = bad、g.rawValue = bad
print("g1 == \(g1)")
print("g1 rawValue == \(g1.rawValue)")
// 隐式原始值,当后边不写是会自动有隐式原始值
enum Grade1: String {
case perfect
case great
case good
case bad
}
/** 等价
enum Grade1: String {
case perfect = "perfect"
case great = "great"
case good = "good"
case bad = "bad"
}
*/
enum Season: Int {
case spring, summer, autumn, winter
}
/**
enum Season: Int {
case spring = 0
case summer = 1
case autumn = 2
case winter = 3
}
*/
enum Season1: Int {
case spring = 1, summer = 4, autumn, winter
}
/**
enum Season: Int {
case spring = 1
case summer = 4
case autumn = 5
case winter = 6
}
*/
4.递归枚举
- 枚举内部用到枚举本身,需要用 indirect 关键字声明
- indirect 可修饰整个枚举、也可修饰部分枚举成员
indirect enum AddEnum1 {
case number(Int)
case sum1(AddEnum1, AddEnum1)
case sum2(AddEnum1, AddEnum1)
}
enum AddEnum2 {
case number(Int)
indirect case sum1(AddEnum2, AddEnum2)
indirect case sum2(AddEnum2, AddEnum2)
}
func calculate(_ e: AddEnum1)->Int {
switch e {
case let .number(value):
return value;
case let .sum1(e1, e2):
return calculate(e1) + calculate(e2);
case let .sum2(e1, e2):
return calculate(e1) + calculate(e2) + 10;
}
}
let three = AddEnum1.number(3)
let four = AddEnum1.number(4)
let sum = AddEnum1.sum1(three, four)
print("递归枚举:\(calculate(sum))")
5.枚举内存探究
- (1)拥有关联值的枚举【关联值内存+类型值内存】
enum Date {
case digit(year: Int, month: Int, day: Int) // 3*8 = 24 bytes
case string(String) // 16 bytes
}
/** Date 内存
digit: 需要24个字节存储关联值
string: 需要16个字节存储关联值
分类内存时,以最大成员值为基准,因此需要24个字节
由于要区分类型digit和string,另需一个字节存储type
因此实际使用 24+1 = 25,内存对其关系:24+8 = 32
因此实际需要一个Date枚举变量需要占用 32个字节
let d:Date = .digit(year: 3, month: 8, day: 10)
0x00 00 00 00 00 00 00 03 // 前8个字节
0x00 00 00 00 00 00 00 08 // 8个字节
0x00 00 00 00 00 00 00 0a // 8个字节
0x00 00 00 00 00 00 00 00 // 最后8个字节(实际只使用一个),存储type
*/
let d:Date = .digit(year: 3, month: 8, day: 10)
print(MemoryLayout.stride(ofValue: d)) // 实际分配 32bytes
print(MemoryLayout.size(ofValue: d)) // 实际使用 25bytes
print(MemoryLayout.alignment(ofValue: d)) // 内存对其参数 8bytes
- (2)由于没有关联值,只需要1个字节存储type即可 【类型值内存】
enum Season {
case spring, summer, autumn, winter
}
let s:Season = .spring
print(MemoryLayout.stride(ofValue: s)) // 实际分配 1bytes
print(MemoryLayout.size(ofValue: s)) // 实际使用 1bytes
print(MemoryLayout.alignment(ofValue: s)) // 内存对其参数 1bytes
- (3)拥有原始值【类型值内存】
enum Seasonsss: String {
case spring = "abc", summer = "bcd", autumn = "sss", winter
var rawValue: String {
switch self {
case .spring:
return "abc"
case .summer:
return "bcd"
case .autumn:
return "sss"
case .winter:
return "winter"
}
}
}
Note:注意,此处虽然有原始值,但实际上枚举变量的原始值并不占用枚举变量的内存空间
枚举变量中任然只需1个字节存储type,即需要(0, 1, 2, ...)
不论有无原始值、关联值都是如此 type:(0, 1, 2, ...)
关联值会占用枚举变量的内存,而原始值则不占用枚举变量的内存
事实上,枚举变量的原始值实现方式与类和结构体重计算属性相同,即方法实现
enum Season1: String {
case spring, summer, autumn, winter
}
let s2:Season1 = .spring
print(MemoryLayout.stride(ofValue: s2)) // 实际分配 1bytes
print(MemoryLayout.size(ofValue: s2)) // 实际使用 1bytes
print(MemoryLayout.alignment(ofValue: s2)) // 内存对其参数 1bytes
print(s2.rawValue)
enum Season: Int {
case spring = 20
case summer = 40
case autumn
case winter
}
Note:类型值
注意:虽然后边写了 20 和 40,但是实际上枚举变量并不会存储该值,在内存中依然为
0,1,2,3,而20, 40则会使用rawValue计算属性(方法)实现
枚举中通常只使用一个字节存储类型值,,0-255,当超过255时,再使用枚举说明设计上有问题,应该更改方案
网友评论