为什么我不能在Objective-C的switch-case语句中使用我的常量?[错误=表达式不是整数常量表达式]

14

我在Objective-C中使用常量变量的switch语句遇到了问题。

我有一个名为Constants.h的文件,内容如下:

// Constants.h    
extern NSInteger const TXT_NAME;

并且 Constants.m 如下:

// Constants.m
#import "Constants.h"

NSInteger const TXT_NAME        = 1;

接下来在TabBasic.m中,我正试图在一个switch-case语句中使用这个常量:

// TabBasic.m

#import "TabBasic.h"
#import "Constants.h"

... code ...

- (IBAction)saveValue:(id)sender {
    if ([sender isKindOfClass: [UITextField class]]) {
        UITextField *txtField = (UITextField *) sender;

        switch (txtField.tag) {
            case TXT_NAME:
                NSLog(@"Set property name to: %@", txtField.text); 
                break;
        }
    }
}

但不幸的是,在"case TXT_NAME:"这一行上,它给了我以下两个错误:

  • 表达式不是整数常量表达式
  • Case标签不能简化为整数常量

有人知道我做错了什么吗?一个UITextField的"tag"变量返回一个NSInteger,所以我不明白问题在哪里...

谢谢你的帮助!

2个回答

22

快速解决方案,应该将NSInteger const TXT_NAME = 1; 放置在 Constants.h 文件中,而不需要在 Constants.m 中添加任何内容。

原因:如果您在 Constants.m 中设置常量的值,则其他仅包含 .h 文件的翻译单元将无法看到它。 常量的值必须在编译时已知,才能在 switchcase 中使用。

更新:

上述方法适用于 Objective-C++ 编译。你需要将文件的后缀名从 .m 改为 .mm,这样它们才会被编译成 Objective-C++ 而不是 Objective-C。

为了在 Objective-C 中工作,您应该像这样定义常量:

#define TXT_NAME 1

或者更好地,像这样定义:

enum {TXT_NAME = 1};


5
如果在多个实现文件中导入constants.h,这种解决方案会导致链接错误。 - Vladimir
4
@Vladimir,实际上这仅适用于在C++中编译时才是真的。 - Thomas
1
@Jules 因为你的 if 语句中的 == 测试不需要在编译时知道常量。而 case: 则需要一个编译时常量值。 - Thomas
3
使用 #define 来定义常量是一个糟糕的想法。常量的目的是将文本视为符号,而不是字符。 - Samuel Goodwin
匿名枚举对我来说是最好的解决方案。而且,如果我想在子类中添加更多值,它也很容易扩展。 - kelin
显示剩余4条评论

10

通常我会遵循苹果的做法,在.h文件中定义一个typedef枚举,就像这样。

typedef NS_ENUM(NSInteger, PSOption) {
  PSOption1,
  PSOption2,
  PSOption3,
  PSOption4,
};  

你可以在case语句中使用它,甚至将其作为类型传递到函数中。

- (void)myMethod:(PSOption)option;

与使用 #define 相比,这种方法的另一个优点是具有代码自动完成和编译器检查的功能。


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