Swift 枚举字节表示是什么?

What is Swift enum byte representation?

我有以下枚举:

enum Enum: UInt8 
{
  case A = 0x00
  case B = 0x01
  case C = 0x10
}

我用下面的代码把它转换成NSData:

var value = Enum.C
let data = NSData(bytes: &value, length: 1)

当然,我希望data包含0x10,然而,它包含0x02.

对于 Enum.A,它包含 0x00,对于 Enum.B,它包含 0x01

对我来说,它看起来像是存储值的索引而不是实际的原始数据。有人可以解释这种行为吗?

P.S。如果我使用 rawValue 它会完美运行。但是,我想了解背后的原因,因为我无法创建通用函数来将值转换为 NSData。

每个枚举案例都有一个标准的顺序值。当你不使用 .rawValue.

时,你会得到什么

例如,如果您将枚举更改为:

enum Enum: UInt8 
{
  case A = 0x00
  case B = 0x01
  case B2 = 0x0A
  case C = 0x10
}

然后,当执行

var value = Enum.C
let data = NSData(bytes: &value, length: 1)

data 将是 3,因为 A = 0B = 1B2 = 2C = 3

Swift ABI 仍在进行中(预计会在 Swift 4 中修复)。枚举在内存中的表示方式 is described here.

您的案例是 "c-like enum" 因为它有...

  • 两个或更多案例
  • 没有关联值

引用 ABI 文档:

the enum is laid out as an integer tag with the minimal number of bits to contain all of the cases. [...] The cases are assigned tag values in declaration order.

这里的关键信息是"minimal number of bits"。这意味着(对于您的情况)实例应该适合两位(因为您有三种情况)。 rawValue 0x10 需要五位——这会与 ABI 冲突。

编译器可能使用静态表在 Enum 实例和它们的 rawValue 实例之间进行转换(以及返回)。

下面是一个突出 ABI 特性的示例:

enum Enum: UInt32
{
    case A = 0
    case B = 0xffffffff    // value that does not fit into one byte
}

assert(sizeof(Enum.self) == 1)