溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

探究Swift枚舉關聯值內存的方法

發布時間:2020-08-19 10:01:55 來源:億速云 閱讀:155 作者:小新 欄目:開發技術

這篇文章將為大家詳細講解有關探究Swift枚舉關聯值內存的方法,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

enum Season {
 case Spring, Summer, Autumn, Winter
}
let s = Season.Spring

這是枚舉最基礎的用法,但是在swift中,對枚舉的功能進行了加強,也就是關聯值。

關聯值可以將額外信息附加到 enum case中,像下面這樣子。

enum Test {
 case test1(v1: Int, v2: Int, v3: Int)
 case test2(v1: Int, v2: Int)
 case test3(v1: Int)
 case test4
}
let t = Test.test1(v1: 1, v2: 2, v3: 3)
 
switch t {
case .test1(let v1, let v2, let v3):
 print(v1, v2, v3)
default:
 break
}
// 輸出: 1 2 3

我們可以看到,在我們創建一個枚舉值t的時候,設置他的選項為test1,同時可以關聯3個Int類型的值,然后在switch中,我們還可以把這3個Int值取出來進行使用。

我們今天的主要任務就是探索一下有關聯值的枚舉類型,再底層的內存布局是什么樣子的,這些值都是怎么儲存的。

在OC中我們使用sizeOf此類方法,可以輸出一個變量占用內存的大小,在swift中也有此類的工作類,那就是MemoryLayout。

print(MemoryLayout<Int>.size)// 實際使用內存大小
print(MemoryLayout<Int>.stride)//分配內存大小
print(MemoryLayout<Int>.alignment)//內存對其參數

// 輸出 8 8 8 

上面的例子是只是簡單的實例MemoryLayout的用法,這個我們知道,在64位的系統中Int類型確實是占用8個字節(64位)。接下來我們就看一下枚舉的內存占用情況。

點擊Xcode菜單欄中的Debug -> Debug Workflow -> View Memory,然后在下面紅色框中輸入變量的內存地址,就可以看到變量的內存使用情況。

使用swift后,從xcode沒法直接打印變量的內存地址,這里我們使用了github上的一個工具類來幫助我們輸出變量的內存地址。

探究Swift枚舉關聯值內存的方法

準備工作完成后,我們先從最基礎的枚舉開始。

enum Season {
 case Spring, Summer, Autumn, Winter
}
print("實際占用:",MemoryLayout<Season>.size)
print("分配:",MemoryLayout<Season>.stride)
print("對齊參數:", MemoryLayout<Season>.alignment)
 
var s = Season.Spring
print("內存地址",Mems.ptr(ofVal: &s))
 
print("內存數據",Mems.memStr(ofVal: &s, alignment: .one))
 
s = Season.Summer
print("內存數據",Mems.memStr(ofVal: &s, alignment: .one))
 
s = Season.Autumn
print("內存數據",Mems.memStr(ofVal: &s, alignment: .one))
 
s = Season.Winter
print("內存數據",Mems.memStr(ofVal: &s, alignment: .one))

注:Mems.memStr可以直接打印內存數據,這樣我們就不用每次拿到地址再去工具中看了

實際占用: 1
分配: 1
對齊參數: 1
內存地址 0x00007ffee753f0f0
內存數據 0x00
內存數據 0x01
內存數據 0x02
內存數據 0x03

我們可以看到這種普通的枚舉類型,只占用一個字節。而且通過我們對變量設置不同的枚舉值,打印的這一個字節的數據也是不同的,其實也就是使用這一個字節通過設置不同的數值來表示不同的枚舉值,這樣的話其實可以至少儲存0x00-0xFF共256個值。那如果超過256個case呢?其實我覺得沒有必要考慮這種情況,枚舉本來設計出就是為了區分有限中情況,如果太多,就像200多個,那完全可以使用Int來設置不同的值了,就沒必要用枚舉了,當然,如果您愿意探究一下的話也是可以的。

接下來我們使用一個帶關聯值的枚舉來看一下。

enum Test {
 case test1(v1: Int, v2: Int, v3: Int)
 case test2(v1: Int, v2: Int)
 case test3(v1: Int)
 case test4
}
 
print("實際占用:",MemoryLayout<Test>.size)
print("分配:",MemoryLayout<Test>.stride)
print("對齊參數:", MemoryLayout<Test>.alignment)
 
var t = Test.test1(v1: 1, v2: 2, v3: 3)
print("內存地址",Mems.ptr(ofVal: &t))
 
print("內存數據",Mems.memStr(ofVal: &t, alignment: .one))
 
t = Test.test2(v1: 4, v2: 5)
print("內存數據",Mems.memStr(ofVal: &t, alignment: .one))
 
t = Test.test3(v1: 6)
print("內存數據",Mems.memStr(ofVal: &t, alignment: .one))
 
t = Test.test4
print("內存數據",Mems.memStr(ofVal: &t, alignment: .one))

下面是輸出, 為了能直觀一下,我給插了幾個換行

實際占用: 25
分配: 32
對齊參數: 8
內存地址 0x00007ffee0afe0d8
內存數據
0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00
內存數據
0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x05 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x01
0x00 0x00 0x00 0x00 0x00 0x00 0x00
內存數據
0x06 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x02
0x00 0x00 0x00 0x00 0x00 0x00 0x00
內存數據
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x03
0x00 0x00 0x00 0x00 0x00 0x00 0x00

實際占用了25個字節,我們至少可以確定,枚舉的關聯值是存儲在枚舉值的內存中的。

但是通過這一個例子其實可能還看不出有什么規律,大家可以多用幾個例子來驗證,這是我就直接說結論了。

有關聯值得枚舉實際占用的內存是最多關聯值占用的內存+1,在我們這個Test中,test1的關聯值是最多的,有3個Int類型的關聯值,所以要8*3=24字節來存放關聯值,但是還需要一個字節來儲存(辨別)是哪一個case。

帶著這個結論我們看一下輸出的結果:

當t=.test1時,前面24個字節分配給3個Int類型關聯值,分別存儲了1,2,3, 第25個字節是0。

當t=.test2時,前面24個字節還是留給關聯值的,但是test2只有兩個關聯值,所以使用了前面16個字節分配給他的關聯值,此時17到24這8字節就空置,第25個字節是1。

...

最后當t = test4 , 沒有關聯值,所以前面的字節都是0, 只有第25個字節是3

以此類推...

第25個字節其實完全可以看成一個辨識位,或者說第25個字節就是枚舉的本質,通過不同值來區分不同case,只是因為有了關聯值,所以開辟了更多的空間來存儲而已。

后面多余的字節都是為了內存對齊,內存對其相關的知識大家可以自行上網查閱。

補充:

既然說到了關聯值,那就順便對枚舉原始值說兩句。具通過你打印帶原始值的枚舉的內存數據,發現是否帶有原始值對枚舉的內存占用并無影響,所以原始值應該不是存儲在枚舉變量的內部的。大家可以自己試驗一下

關于探究Swift枚舉關聯值內存的方法就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女