【问题标题】:Behavior of Objective-C enum "exhaustive" switch without a default case没有默认情况的 Objective-C 枚举“详尽”开关的行为
【发布时间】:2019-06-16 12:44:49
【问题描述】:

在 Swift 中,init(rawValue:) 系统确保将 Int 强制转换为枚举要么导致有效的枚举大小写,要么导致 nil

在 Objective-C 中没有这样的安全性,可以通过强制转换非成员“rawValue”来创建无效的枚举成员。

typedef NS_ENUM(NSInteger, ExampleEnum) {
    first = 0,
    second,
    third,
};

+ (NSString *)stringForCase:(ExampleEnum)enumCase {
    switch (enumCase) {
        case first:  return @"first";
        case second: return @"second";
        case third:  return @"third";
    }
}

+ (void)testEnum {
    ExampleEnum invalidCase = (ExampleEnum)3; // this "rawValue" is out of bounds
    NSString *string = [self stringForCase:invalidCase]; // nil
}

打开枚举时,如果未处理枚举情况,编译器会警告您:

枚举值“第三个”未在开关中处理

但是一旦处理了所有情况,就没有类似的警告表明枚举的无效成员仍然可能出现“默认”情况。

在这种情况下的行为是什么? NSString 方法似乎返回nil,并且没有观察到崩溃。但是该方法没有returnreturn nil是自动生成的吗,在什么情况下?

请注意,“详尽”开关之后的代码语句不会导致通常会生成警告:

代码永远不会被执行

【问题讨论】:

  • 切向,但您可能对这篇博文感兴趣(快速阅读):owensd.io/2014/10/09/building-swift-style-enums-in-objc-part-3
  • "但是如果出现一些 hack 并在我漂亮的函数中抛出一个未初始化的 int 怎么办?" - softwareengineering.stackexchange.com/questions/179269/…
  • 旁白:FWIW,在考虑 C(或 ObjC)中的枚举时,与大量其他语言中的枚举不同,它们在概念上并不是真正的“特殊”类型——认为枚举只是整数的语法糖 some 有用的编译器警告围绕它们的使用,但还有其他陷阱。对不在定义的枚举集中的值使用一些随机整数并不是“无效”,因为它只是编写(或设计)错误的代码。由于这种设置,枚举在 C 中是一种痛苦,而且几乎所有后来的语言(包括 Swift)都使枚举更加一流和有用。

标签: c objective-c enums switch-statement


【解决方案1】:

TL;DR,如果没有匹配的情况,该函数确实将控制权返回给调用者,但返回值是undefined .

C/ObjC return 语句基本上做了两件事。它会导致将其值放入特定位置,以便调用者知道在哪里查找它。 (由平台/语言 ABI 定义的位置。)然后它将控制权移回调用函数(通过从堆栈中弹出一个地址并跳转到它)。

在这种情况下,控制将直接越过switch 的末尾,并且不会执行任何return 语句。然而,编译器确实会在方法结束时发出一个跳转。

(事实上——我不擅长阅读汇编程序,但是——我看到 Xcode 10.1 为您的代码创建的带调试注释的汇编程序将所有开关案例集中到该方法的单个退出点。而且如果没有一个案例比较成功,到达退出点。)

但是我们在没有将任何值放入返回寄存器的情况下进行了跳转,这意味着它与任何其他未初始化的值相同——垃圾。您可靠地获得nil 的事实可能是由于您的测试程序的简单性和在调试配置中构建的一个或两个原因。

【讨论】:

  • 很高兴知道我得到的nil 结果的未定义性质。您是否知道这个确切的主题已在其他地方报道/写过?
  • 老实说不确定,但这是直接的 C 行为;在这种情况下,ObjC 没有什么特别之处,所以它可能在某个地方的 C 标准中。
  • 实际上,现在我想到了,ARC 有可能保证nil,因为返回类型是一个对象......(就像未初始化的对象指针一样)。不确定;我得花点时间看看 ARC 规范。
  • 我在 ARC 文档中发现了可能发生这种情况的提示,但我不确定。我再看看汇编程序的输出,看看能不能搞清楚。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-19
  • 1970-01-01
  • 2011-11-30
  • 2021-09-22
  • 1970-01-01
  • 2018-09-16
相关资源
最近更新 更多