枚举的基本使用
import UIKit
enum Direction {
case north
case south
case west
case east
}
enum Direction1 {
case north,south,west,east
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var dir = Direction.north
dir = Direction.west
//枚举类型可以省略
dir = .south
print(dir)
switch dir {
case .north:
print("north")
case .south:
print("south")
case .west:
print("west")
default:
print("east")
}
}
}
关联值
- 关联值:将
枚举的成员值
与其他类型的数值关联存储在一起
的值,称之为枚举的关联值
;
import UIKit
enum Score{
case points(Int)
case grade(Character)
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var score = Score.points(100)
score = Score.grade("A")
print("score = \(score)")
switch score {
case let .points(i):
print("point = \(i)")
case let .grade(i):
print("grade = \(i)")
}
}
}
- Score枚举有两种类型,一种是分值表示,另一种是字符表示;
-
case let .points(i):
表示当枚举变量score
为case points(Int)
枚举类型时,取出此时枚举变量的关联值,赋值给常量i,注意let是用来修饰接收 枚举关联值 的常量i的;
enum Date {
case digit(year: Int,month: Int,day: Int)
case string(String)
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var date = Date.digit(year: 2021, month: 7, day: 29)
date = Date.string("2020-09-24")
switch date {
case .digit(let year, let month, let day):
print("\(year) - \(month) - \(day)")
case let .string(value):
print("\(value)")
}
}
}
enum Password {
case number(Int,Int,Int,Int)
case gersure(String)
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var password = Password.number(1, 2, 3, 4)
password = Password.gersure("123456789")
switch password {
case let .number(n1, n2, n3, n4):
print("number is",n1,n2,n3,n4)
case let .gersure(value):
print(value)
}
}
}
原始值
- 枚举成员可以使用相同类型的默认值预先关联,这个默认值叫做原始值;
enum Grade : String{
case perfect = "A"
case great = "B"
case good = "C"
case bad = "D"
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print(Grade.perfect.rawValue) //A
print(Grade.great.rawValue) //B
print(Grade.good.rawValue) //C
print(Grade.bad.rawValue) //D
}
}
隐式原始值
enum Direction2 : String {
case north,south,west,east
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print(Direction2.north.rawValue) //north
print(Direction2.south.rawValue) //south
print(Direction2.west.rawValue) //west
print(Direction2.east.rawValue) //east
}
}
- 上面这种写法,会默认给对应的枚举类型设置原始值,原始值与枚举类型的名称相同;
enum Season : Int {
case spring,summer,autum,winter
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print(Season.spring.rawValue) //0
print(Season.summer.rawValue) //1
print(Season.autum.rawValue) //2
print(Season.winter.rawValue) //3
}
}
递归枚举
indirect enum MathOpeartion {
case number(Int)
case sum(MathOpeartion,MathOpeartion)
case diff(MathOpeartion,MathOpeartion)
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let n1 = MathOpeartion.number(10)
let n2 = MathOpeartion.number(20)
let sum = MathOpeartion.sum(n1, n2)
let result = calculate(sum)
print(result)
}
func calculate(_ mathExpr: MathOpeartion) -> Int {
switch mathExpr {
case let .number(value):
return value
case let .sum(n1, n2):
return calculate(n1) + calculate(n2)
case let .diff(n1, n2):
return calculate(n1) - calculate(n2)
}
}
}
MemoryLayout
enum Season : Int {
case spring,summer,autum,winter
}
enum Password {
case number(Int,Int,Int,Int)
case gersure(String)
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let a = 10
print(MemoryLayout.size(ofValue: a)) //8
print(MemoryLayout.stride(ofValue: a))//8
print(MemoryLayout.alignment(ofValue: a))//8
print(MemoryLayout.size)//1
print(MemoryLayout.stride)//1
print(MemoryLayout.alignment)//1
print(MemoryLayout.size) //33
print(MemoryLayout.stride) //40
print(MemoryLayout.alignment) //8
}
}
-
MemoryLayout.size()
:获取目标实际的内存大小;
-
MemoryLayout.stride()
:获取目标分配的内存大小,会使用内存对其算法;
-
MemoryLayout.alignment()
:获取内存对其参数;
-
Password
枚举类型变量所占用的内存大小与其关联值相关,number类型有4个Int类型,占用32个字节点,额外的一个字节是用来区分gesure类型的,总共实际占33个字节,gesure是字符串类型,33个字节完全能存储字符串,此枚举感觉跟C语言中的共用体很相似;
-
Season
枚举类型变量只占用一个字节,与原始值Int类型没什么关系,内存用一个字节就完全能区分Season枚举类型的所有枚举;
枚举变量的内存布局
最普通的情况:
enum Season {
case spring,summer,autum,winter
}
import Foundation
var a: Int = 10
a = 20
var season = Season.spring
season = Season.summer
season = Season.autum
print(season)
- 当断点停在
season = Season. summer
所在行时,查看内存布局如下所示:
- Int类型变量a占用8个字节,枚举变量season占用一个字节;
- 当断点停在
season = Season.autum
所在行时,内存布局如下:
枚举使用原始值的情况,代码如下:
enum Season : Int{
case spring = 2,summer,autum,winter
}
import Foundation
var a: Int = 10
a = 20
var season = Season.spring
season = Season.summer
season = Season.autum
print(season)
- 当断点停在
season = Season.summer
所在行时,查看内存布局如下所示:
- 当断点停在
season = Season.autum
所在行时,内存布局如下:
- 可以看出原始值是不会存储到枚举变量中的,不会影响枚举变量的内存布局;
枚举使用关联值的情况
enum TestEnum{
case test1(Int,Int,Int)
case test2(Int,Int)
case test3(Int)
case test4(Bool)
case test5
}
import Foundation
var a: Int = 10
a = 20
print(MemoryLayout.size) //25
print(MemoryLayout.stride) //32
print(MemoryLayout.alignment) //8
var test = TestEnum.test1(1, 2, 3)
test = TestEnum.test2(4, 5)
test = TestEnum.test3(6)
test = TestEnum.test4(true)
test = TestEnum.test5
- 当断点停在
test = TestEnum.test2(4, 5)
所在行,内存布局如下所示:
- 前面8个字节存储的是整型变量a的值;
- 紧接着24个字节存储的是枚举变量test的三个关联值1,2,3,最后一个字节存储的是枚举类型的成员值,即枚举变量在枚举类型中的类型,值为0;
- 当断点停在
test = TestEnum.test3(6)
所在行,内存布局如下所示:
- 前面8个字节存储的是整型变量a的值;
- 紧接着24个字节存储的是枚举变量test的三个关联值4,5,0,最后一个字节存储的是枚举类型的成员值,即枚举变量在枚举类型中的类型,值为1;
- 以此类推,就很容易推断出后面枚举变量在内存的中布局情况了;
- 总结:
- 当枚举变量中存在多个枚举类型时,枚举变量会单独占用一个字节,用来存储枚举变量在枚举中的成员值;如果只有一个枚举时,就不需要单独占用一个字节了;
- N个字节存储关联值(N取占用内存最大的关联值),枚举中任何一个case的关联值都共用这N个字节,与C语言中的共用体类似;