Swift底層原理-枚舉
枚舉基本用法
- 在
Swift
中可以通過enum
關(guān)鍵字來聲明一個(gè)枚舉鲤妥,如下:
enum Season {
case spring
case summer
case autumn
case winter
}
var season: Season = .spring
原始值
- 枚舉的
原始值
特性可以將枚舉值
與另一個(gè)數(shù)據(jù)類型
進(jìn)行綁定 - 在
Swift
中的枚舉則更加靈活杆逗,并且不需要給枚舉中的每一個(gè)成員都提供值荸型,如果要為枚舉成員提供值,那么這個(gè)值可以是字符串挎扰,字符或者浮點(diǎn)類型等等氓轰;
enum Season: String {
case spring = "spring"
case summer = "summer"
case autumn = "autumn"
case winter = "winter"
}
var season: Season = .spring
print(season.rawValue)
打印結(jié)果:spring
- 在枚舉
Season
的后面加上:
并指定具體的類型峰伙,這個(gè)時(shí)候枚舉的原始值默認(rèn)就是指定的類型。我們可以通過rawValue
拿到枚舉成員的原始值程帕。
隱式原始值
- 如果枚舉的原始值類型是
Int
住练、String
,Swift
會(huì)自動(dòng)分配原始值骆捧,隱式RawValue
分配是建立在Swift
的類型推斷機(jī)制上的澎羞。
String類型
- 例如枚舉
Season
可以如下定義
enum Season: String {
case spring
case summer
case autumn
case winter
}
print(Season.spring.rawValue) // spring
print(Season.summer.rawValue) // summer
print(Season.autumn.rawValue) // autumn
print(Season.winter.rawValue) // winter
- 默認(rèn)將原始值設(shè)置為枚舉值一樣
Int類型
- 如果枚舉Seacon定義為如下
enum Season: Int {
case spring
case summer
case autumn
case winter
}
print(Season.spring.rawValue) // 0
print(Season.summer.rawValue) // 1
print(Season.autumn.rawValue) // 2
print(Season.winter.rawValue) // 3
- 枚舉的原始值是
Int
類型的,自動(dòng)分配的原始值從第一個(gè)成員開始敛苇,下標(biāo)從 0 計(jì)算妆绞,依次 +1 - 如果假設(shè)把
autumn
指定為5,那么從autumn
開始枫攀,下標(biāo)從5開始計(jì)算括饶,依次+1
enum Season: Int {
case spring
case summer
case autumn = 5
case winter
}
print(Season.spring.rawValue) // 0
print(Season.summer.rawValue) // 1
print(Season.autumn.rawValue) // 5
print(Season.winter.rawValue) // 6
關(guān)聯(lián)值
-
Swift
中枚舉值可以跟其他類型關(guān)聯(lián)起來存儲(chǔ)在一起,從而來表達(dá)更復(fù)雜的案例来涨。
enum Season {
case spring(month: Int)
case summer(startMonth: Int, endMonth: Int)
}
- 我們可以在枚舉值后面跟上你需要的一些參數(shù)图焰,比如說
summer
關(guān)聯(lián)了起始月份和中止月份兩個(gè)參數(shù)
var sping: Season = Season.spring(month: 1)
switch sping {
case .spring(let month):
print(month)
case .summer(let startMonth, let endMonth):
print(startMonth, endMonth)
}
- 在使用
switch
的時(shí)候,我們可以在case
的后面加上let
或者var
蹦掐,將枚舉的關(guān)聯(lián)值取出或者修改技羔。
關(guān)聯(lián)值和原始值的區(qū)別
枚舉的關(guān)聯(lián)值和原始值在本質(zhì)上的區(qū)別就是,關(guān)聯(lián)值占用枚舉的內(nèi)存卧抗,而原始值不占用枚舉的內(nèi)存藤滥。
并且 rawValue 本質(zhì)上是一個(gè)計(jì)算屬性。舉個(gè)例子社裆,
rawValue
的實(shí)現(xiàn)大概應(yīng)該是這樣子的:
enum Season: Int {
case spring, summer, autumn , winter
var rawValue: Int {
get {
switch self {
case .spring:
return 10
case .summer:
return 20
case .autumn:
return 30
case .winter:
return 40
}
}
}
}
枚舉內(nèi)存大小
- 接下來我們探討一下枚舉的內(nèi)存大小拙绊,探討的過程中分三種情況:第一種是無關(guān)聯(lián)值的枚舉;第二種是只有一個(gè)關(guān)聯(lián)值的枚舉;第三種是有多個(gè)關(guān)聯(lián)值的枚舉标沪。
無關(guān)聯(lián)值的枚舉
enum Season {
case spring
case summer
case autumn
case winter
}
print(MemoryLayout<Season>.size) // 1
print(MemoryLayout<Season>.stride) // 1
- 通過打印榄攀,當(dāng)前枚舉的內(nèi)存大小為1個(gè)字節(jié)。無關(guān)聯(lián)值的枚舉默認(rèn)是以一個(gè)字節(jié)的方式去存儲(chǔ)金句,1個(gè)字節(jié)可以存儲(chǔ)256個(gè)
case
檩赢。如果超出這個(gè)現(xiàn)實(shí),枚舉會(huì)升級成2個(gè)字節(jié)去存儲(chǔ)趴梢。
只有一個(gè)關(guān)聯(lián)值的枚舉
enum Season {
case spring(Bool)
case summer
case autumn
case winter
}
print(MemoryLayout<Season>.size) // 1
print(MemoryLayout<Season>.stride) // 1
- 當(dāng)枚舉的關(guān)聯(lián)值為
Bool
類型時(shí)漠畜,枚舉只占 1 個(gè)字節(jié)。對于Bool
類型來說坞靶,它本身是 1 個(gè)字節(jié)的大小憔狞,但實(shí)際上它只需要 1 位來存儲(chǔ)Bool
值,而且由于此時(shí)的枚舉是以UInt8
的方式進(jìn)行存儲(chǔ)彰阴,在這 8 位當(dāng)中瘾敢,有 1 位是用來存儲(chǔ)Bool
值的,余下的 7 位才是用來存儲(chǔ)case
的尿这,那此時(shí)這個(gè)枚舉最多只能有 128 個(gè)case
簇抵。
- 當(dāng)枚舉的關(guān)聯(lián)值為
int
類型時(shí)
enum Season {
case spring(Int)
case summer
case autumn
case winter
}
print(MemoryLayout<Season>.size) // 9
print(MemoryLayout<Season>.stride) // 16
- 當(dāng)枚舉的關(guān)聯(lián)值為
Int
類型時(shí),枚舉占用 9 個(gè)字節(jié)射众。對于Int
類型來說碟摆,其實(shí)系統(tǒng)是沒有辦法推算當(dāng)前負(fù)載所要使用的位數(shù),這個(gè)時(shí)候我們就需要額外開辟內(nèi)存空間來存儲(chǔ)我們的case
值叨橱。
多個(gè)關(guān)聯(lián)值的枚舉
enum Season1 {
case spring(Bool)
case summer(Bool)
case autumn(Bool)
case winter(Bool)
}
enum Season2 {
case spring(Int)
case summer(Int)
case autumn(Int)
case winter(Int)
}
enum Season3 {
case spring(Bool)
case summer(Int)
case autumn
case winter
}
enum Season4 {
case spring(Int, Int, Int)
case summer
case autumn
case winter
}
print(MemoryLayout<Season1>.size) // 1
print(MemoryLayout<Season2>.size) // 9
print(MemoryLayout<Season3>.size) // 9
print(MemoryLayout<Season4>.size) // 25
- 如果枚舉中多個(gè)成員有關(guān)聯(lián)值典蜕,且最大的關(guān)聯(lián)值類型大于 1 個(gè)字節(jié)(8 位)的時(shí)候,此時(shí)枚舉的大小為:最大關(guān)聯(lián)值的大小 + 1罗洗。
特殊情況
enum Season {
case season
}
print(MemoryLayout<Season>.size) // 0
- 對于當(dāng)前的
Season
只有一個(gè)case
愉舔,此時(shí)不需要用任何東?來去區(qū)分當(dāng)前的case
,所以當(dāng)我們打印當(dāng)前的Season
大小是 0伙菜。