前言:
本篇僅為視頻學(xué)習(xí)筆記
短接上篇:
★ iOS高級(jí):Swift入門精講③ 01 swift編程-05-枚舉-04原始值內(nèi)存分布
★ 這個(gè)原始值命咐,它存儲(chǔ)到什么地方呢仍劈?(無(wú)需糾結(jié))
enum Season: Int {
case spring = 1, summer, autumn, winter
}var s = Season.spring var s1 = Season.spring var s2 = Season.spring s2.rawValue MemoryLayout<Season>.size // 1,實(shí)際用到的空間大小 MemoryLayout<Season>.stride // 1,分配占用的空間大小 MemoryLayout<Season>.alignment // 1,對(duì)齊參數(shù)
我們把它改成上面代碼那樣,冒號(hào)Int揭鳞。(enum Season: Int)。不就是代表枚舉Season的原始值是Int類型嗎梆奈,所以呢野崇,我們寫了一個(gè)原始值spring = 1。summer, autumn, winter依次默認(rèn)為2亩钟、3乓梨、4。
之前径荔,說(shuō)過(guò)督禽,這個(gè)原始值不是存儲(chǔ)到s變量里面去的。像這些枚舉變量总处。它只占用一個(gè)字節(jié)狈惫,它一個(gè)字節(jié)就能搞的清楚,它是spring鹦马,是summer胧谈,是autumn,還是winter荸频。
那你可能就會(huì)想菱肖,那么這個(gè)原始值存儲(chǔ)到哪里呢?其實(shí)這個(gè)東西旭从,你思考一下稳强,它不存也可以啊,怎么不存也可以呢和悦?
因?yàn)橥艘撸阆胂耄隳迷贾挡贿^(guò)就是調(diào)用 s2.rawValue鸽素。那么這個(gè)rawValue褒繁,完全怎么可以實(shí)現(xiàn)呢?
完全可以這樣實(shí)現(xiàn)馍忽,如下代碼:
enum Season: Int { case spring = 1, summer, autumn, winter func rawValue() -> Int { if self == 0 return 1 if self == 1 return 2 if self == 2 return 3 if self == 3 return 4 } }
所以棒坏,完全可以不用思考燕差,它存在什么地方,它完全可以不用存坝冕。
是不是可以這個(gè)樣子徒探,如果發(fā)現(xiàn)我自己內(nèi)存里面存儲(chǔ)的是0,也就是存儲(chǔ)的是spring喂窟,我們就return 1刹帕。那么,如果我發(fā)現(xiàn)自己內(nèi)存里谎替,存儲(chǔ)的是1,不就意味著我是summer蹋辅,我是summer钱贯,那么我的原始值就是return 2。那么我這個(gè)rawValue獲取原始值的實(shí)現(xiàn)內(nèi)部完全可以如上面代碼那樣寫侦另。
所以秩命,大家沒(méi)有必要去糾結(jié),如果這里寫的是enum Season:String,那么你關(guān)聯(lián)的這個(gè)原始值褒傅,它存儲(chǔ)到什么地方呢弃锐?它不一定需要存儲(chǔ)殿托。所以,這個(gè)放哪里支竹,這個(gè)跟你無(wú)關(guān)。你只要搞清楚礼搁,這個(gè)枚舉變量占用多少內(nèi)存就可以了饶碘。
★ Password枚舉為什么實(shí)際用到的空間大小為33個(gè)字節(jié)呢?
enum Password { case number(Int,Int,Int,Int) // 32 case other // 1 } var pwd = Password.number(5, 6, 4, 7) // 占用32字節(jié) pwd = .other var pwd1 = Password.number(2, 4, 3, 0) // 占用32字節(jié) var pwd2 = Password.number(23, 43, 133,30) // 占用32字節(jié) MemoryLayout<Password>.stride // 40扎运,分配占用的空間大小 MemoryLayout<Password>.size // 33饮戳,實(shí)際用到的空間大小 MemoryLayout<Password>.alignment // 8豪治,對(duì)齊參數(shù)
再說(shuō)另外一個(gè)問(wèn)題,剛剛說(shuō)到Password這個(gè)枚舉變量的話莹捡,那么我定義一個(gè)pwd枚舉變量鬼吵。最后真正分配的內(nèi)存是多少? 是40,但實(shí)際上真正利用起來(lái)的是33齿椅。其實(shí)這個(gè)33是怎么利用起來(lái)的呢?
我們?cè)? case number(Int,Int,Int,Int) 這個(gè)位置標(biāo)記一個(gè)32涣脚,是沒(méi)有問(wèn)題的。但是我們?cè)赾ase other // 1標(biāo)記一個(gè)1的話矾麻,其實(shí)不是很嚴(yán)謹(jǐn)芭梯。那么這個(gè)1险耀,這個(gè)字節(jié)是怎么用的呢甩牺?
其實(shí)累奈,有的人會(huì)怎么想呢?它會(huì)想澎媒,你這個(gè)pwd這個(gè)枚舉變量,只占用32個(gè)字節(jié)请敦,不就夠了嗎储玫?為什么呢?首先缘缚,如果你的pwd是 case number(Int,Int,Int,Int) 這種類型的話4個(gè)證書,剛好是32個(gè)字節(jié)窝爪,存儲(chǔ)到里面去。但是蒲每,如果你是other的話喻括,大家有可能會(huì)想,像下面這種:
enum Password { case other, abc, ddd }
非常普通的這些成員望蜡,他是不是只需要一個(gè)字節(jié)就夠了。比如說(shuō)脖律,other是0、abc是1芦疏,ddd是2微姊。是不是用一個(gè)字節(jié),就能把這些數(shù)值表達(dá)清楚了兢交。那么,一說(shuō)到這個(gè),大家可能會(huì)想与倡,那么你存儲(chǔ)other只需要1個(gè)字節(jié)纺座,但是在var pwd = Password.number(5, 6, 4, 7) 這行時(shí),我們不是已經(jīng)分配了32個(gè)字節(jié)給pwd了嗎净响?
那么你的.other賦值給pwd。( pwd = .other )赞别,就不能將這個(gè)other配乓,1個(gè)字節(jié)的數(shù)據(jù)存儲(chǔ)到var pwd = Password.number(5, 6, 4, 7) 這32個(gè)字節(jié)里面去嗎?肯定會(huì)有這樣的問(wèn)題犹芹,有這樣的問(wèn)題說(shuō)明你還沒(méi)想透。
你思考一下飒焦,如果你將 .other 這一個(gè)值屿笼。假設(shè)你這個(gè)值 case other是 0翁巍。那么志电,你能把這個(gè)0存儲(chǔ)到剛剛 Password.number(5, 6, 4, 7) 32個(gè)字節(jié)里面去嗎?
那我就問(wèn)你將來(lái)你怎么判斷呢例朱?你怎么知道鱼蝉,它是.otner還是 .number呢?根本就分不清渔隶。請(qǐng)問(wèn)我現(xiàn)在給你32個(gè)字節(jié)洁奈,你怎么知道32個(gè)字節(jié)里面存儲(chǔ)的是.otner這個(gè)家伙還是這(5, 6, 4, 7) 四個(gè)家伙。
因?yàn)槟隳玫?2利术,完全可以把這32個(gè)字節(jié)分成4個(gè)部分印叁,每個(gè)部分8個(gè)字節(jié),然后分別認(rèn)為是這(Int,Int,Int,Int) 四個(gè)整型轮蜕。
我也可以拿到32個(gè)字節(jié)中,最前面的一個(gè)字節(jié)率触,當(dāng)作是 .other汇竭。所以,你必須var pwd = Password.number(5, 6, 4, 7) // 32 + 1 其中的一個(gè)字節(jié)是來(lái)告訴你是case other,這個(gè)類型韩玩,還是case number(Int,Int,Int,Int) // 32 這個(gè)類型。你可以這樣思考合愈,這是用來(lái)辨別的。就是從字節(jié)中益老,我們可以看得出來(lái)寸莫,我們整體數(shù)據(jù)是case number(Int,Int,Int,Int) 這個(gè)家伙,還是case other這個(gè)家伙膘茎。
所以,只給它enum Password 32個(gè)字節(jié)是不行的态坦。所以棒拂,必然是32 + 1,那么谜诫,你可能會(huì)想為什么不是 32 + 2呢攻旦?沒(méi)必要這么浪費(fèi),你搞出一個(gè)來(lái)敬特,就行了牺陶。
既然,你需要占用33個(gè)字節(jié)皱炉,再加上它的內(nèi)存對(duì)齊參數(shù)是8個(gè)字節(jié)狮鸭,所以最后分配給它的是40個(gè)字節(jié)。