站在汇编角度深入了解 Swift(四)

329 阅读3分钟

思考下面的枚举变量的内存布局

enum TestEnum {
    case test1, test2, test3
}
var t = TestEnum.test1
t = .test2
t = .test3
print(MemoryLayout.size(ofValue: t)) 
print(MemoryLayout.stride(ofValue: t)) 
print(MemoryLayout.alignment(ofValue: t)) 
print(UnsafeMutablePointer(&t))
---------------执行结果------------------
1
1
1
0x00007ffeefbff438
x/1xg 0x7ffeefbff438
0x7ffeefbff438: 0x0000000000000002 // 从这里可以看出只需要一个字节就能把这个枚举表达出来了
enum TestEnum {
    case test1(Int, Int, Int)
    case test2(Int, Int)
    case test3(Bool)
    case test4
}
var t1 = TestEnum.test1(10, 11, 12)
var t2 = TestEnum.test3(true)
var t3 = TestEnum.test4

print(MemoryLayout.size(ofValue: t1))
print(MemoryLayout.stride(ofValue: t1))
print(MemoryLayout.alignment(ofValue: t1))

print(UnsafeMutablePointer(&t1))
print(UnsafeMutablePointer(&t2))
print(UnsafeMutablePointer(&t3))

---------------执行结果------------------
25
32
8
0x00007ffeefbff420
0x00007ffeefbff400
0x00007ffeefbff3e0
(lldb) x/12wg 0x00007ffeefbff3e0
0x7ffeefbff3e0: 0x0000000000000000 0x0000000000000000
0x7ffeefbff3f0: 0x0000000000000000 0x0000000000000003
0x7ffeefbff400: 0x0000000000000001 0x0000000000000000
0x7ffeefbff410: 0x0000000000000000 0x00007ffeefbff402
0x7ffeefbff420: 0x000000000000000a 0x000000000000000b
0x7ffeefbff430: 0x000000000000000c 0x0000000000000000
enum TestEnum {
    case test1(Bool)
    case test2(Int, Bool)
}
var t1 = TestEnum.test1(true)
var t2 = TestEnum.test2(1, true)
var t3 = TestEnum.test1(false)
print(UnsafeMutablePointer(&t1))
print(UnsafeMutablePointer(&t2))
print(UnsafeMutablePointer(&t3))
print(MemoryLayout.size(ofValue: t1))
print(MemoryLayout.stride(ofValue: t1))
print(MemoryLayout.alignment(ofValue: t1))

---------------执行结果------------------
0x00007ffeefbff430
0x00007ffeefbff420
0x00007ffeefbff410
9
16
8
(lldb) x/8wg 0x00007ffeefbff400
0x7ffeefbff400: 0x0000000000000001 0x00007fff8afcb9e0
0x7ffeefbff410: 0x0000000000000000 0x00007ffeefbff400
0x7ffeefbff420: 0x0000000000000001 0x0000000000000081
0x7ffeefbff430: 0x0000000000000001 0x0000000000000000
  • 枚举所需要的内存就是存储关联值所需要的字节数(取每个位上面占用最多的字节,任何一个 case 的关连值都共用这几个字节)的和加上成员值(1个字节)所需要的字节数。
  • 有时候会将枚举的成员值跟其他类型的值关联存储在一起,会非常有用
  • 原始值(rawValue)不占用枚举变量的内存
  • 特别注意:如果一个枚举里面只有一个case,并且没有关联值,那么它实际占用的内存为0个字节,系统会分配一个字节,字节对齐也是一个字节(因为只要有就知道是他,所以不需要浪费额外的内存再去存储了)

那么是如何通过 rawValue 来获取原始值的呢?

和存储属性一样。

如何将 enum 中的关联值取出来

  • 先去根据类型,找到成员值存储在内存中的哪一字节中,然后判断是哪一个case,最后再将其他的内存中的值依次传入case的参数中。