什么是Swift枚举字节表示?

3

我有以下枚举:

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
在我看来,它似乎存储的是值的索引而不是实际的原始数据。有谁能解释这种行为吗?
顺便说一下,如果我使用rawValue,它可以完美地工作。然而,由于这个原因,我不能创建一个通用的函数将值转换为NSData,并且我想理解其背后的原因。

在这种情况下,值的大小以字节为单位恰好为1(我使用了sizeof而不是1)。因此,这意味着保存的唯一内容是订单号。 - Werolik
2个回答

3
Swift ABI仍在不断改进中(预计会在Swift 4中得到解决)。枚举类型在内存中的表示方式可以在这里找到。
你的情况属于“类C枚举”,因为它有两个或更多的case,并且没有关联值。
引用ABI文档中的话:
“该枚举类型被布局为一个整数标记,其具有包含所有情况的最小位数。 [...] 情况按声明顺序分配标记值。”
这里的关键信息是“最小位数”。这意味着(对于你的情况)实例应该适合两个位(因为你有三种情况)。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)

这解释清楚了,谢谢。看起来我需要使用特定的RawValueRepresentable重载将枚举转换为NSData。 - Werolik
@Werolik 现在看来,不依赖 ABI 特定的内容来构建这种通用转换函数似乎是个好主意。 - Nikolai Ruhe

1
每个枚举值都有一个标准的顺序值。当您不使用.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


1
你能提供一些相关文档来参考吗? - Werolik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接