当前位置: 首页 > 知识库问答 >
问题:

没有默认大小写的Objective-C枚举“穷举”开关的行为

文喜
2023-03-14

在Swift中,init(rawValue:)系统可确保将Int转换为enum会导致有效的enum case或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
}

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

枚举值“third”未在开关中处理

但是,一旦处理完所有案例,就不会有类似的警告,表明对于枚举的无效成员仍然可能出现“默认”案例。

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

请注意,“穷举”开关后的代码语句不会产生通常会生成的警告:

永远不会执行代码

共有1个答案

莫宝
2023-03-14

TL;DR,如果没有匹配的情况,函数会将控制返回给调用方,但返回值未定义。

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

在这种情况下,控件将直接走过开关的末尾,并且不会执行返回语句。但是,编译器确实会为方法的末尾发出跳转。

(事实上,我并不擅长阅读汇编程序,但我看到Xcode 10.1为代码创建的带调试注释的汇编程序会将所有切换情况汇集到该方法的一个退出点。如果没有任何情况比较成功,也会到达该退出点。)

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

 类似资料:
  • 主要内容:1. Objective-C集合快速枚举是Objective-C的功能,用于枚举集合。 因此,要了解快速枚举,首先需要了解集合,这将在下一节中进行说明。 1. Objective-C集合 集合是基本结构。它用于保存和管理其他对象。 集合的主要目的是提供一种有效存储和检索对象的通用方法。 有几种不同类型的集合。 虽然它们都能实现能够容纳其他对象的相同目的,但它们的主要区别在于检索对象的方式。 Objective-C中使用的最常见的

  • 我的api如下所示: 对于查询,我们只想允许查询枚举中列出的某些属性,如下所示: 我加了 在启动阶段。cs,但这不适用于默认值,我得到以下生成的虚张声势,默认值为0而不是字符串: 如何使默认值显示为字符串?

  • 问题内容: 我们有一个带有枚举字段-的实体,我们想使用JPA注释-为它设置默认值。 但是,当我们将实体保存到数据库时,此字段的值为和。对于布尔字段- 正确的默认值()已保存。 如果改为使用:,则会在保存时得到以下异常: 我们做错了什么?为什么它仅适用于布尔值? 问题答案: 当某些SQL代码在未为emailCommunicationStatus列指定任何值的情况下插入一行时,您所做的工作很有用。在这

  • 我正在尝试检查我的VO中设置了哪些值。 下面是我的女儿。我得到的是“合格的病例标签MyEnum.UserType.Doctors必须替换为不合格的枚举常量Doctors” EnumTest.java

  • 错误:枚举开关大小写标签必须是枚举常量的非限定名称错误:大小写标签重复 不要编译,帮帮我!

  • 类型过去是字符串。但我将它切换为枚举,它破坏了我的switch语句。请救救我,我快死了。