在 Objective-C 中创建常量的最佳方法是什么

我正在创建一个学习目的的 Reddit 客户端。我需要一个包含常量的文件。我在考虑导入 Reddit-Prefix.pch文件中的文件,以使所有文件都可以使用这些常量。这样做好吗?另外,我做了一些研究,找到了几种创建常量的方法,但是我不知道该使用哪一种:

  • #define
  • const
  • static const
  • extern const
  • enum

那么哪种方式更好呢?大会是什么?我知道“这取决于”,但我的问题更具体地说是: 每个解决方案的用例是什么?

另外,如果使用 extern const,我是否需要导入文件,或者常量将在不导入文件的情况下全局可用?

我可以从逻辑上得出的一个结论是,在定义自定义错误域之类的东西时,enum是最佳选择(我说得对吗?).那其他人呢?

72430 次浏览

第一个问题是您希望常量具有什么作用域,这实际上是两个问题:

  • 这些常量是特定于单个类的,还是在应用程序中到处使用它们有意义?
  • 如果它们是特定于类的,它们是供类的客户端使用,还是仅在类内使用?

如果它们是特定的并且是单个类的内部的,则在。M 文件,如下所示:

static NSString *const MyThingNotificationKey = @"MyThingNotificationKey";

如果它们属于单个类,但应该是 public/由其他类使用,则在头部声明它们为 extern,并在。米:

//.h
extern NSString *const MyThingNotificationKey;


//.m
NSString *const MyThingNotificationKey = @"MyThingNotificationKey";

如果它们应该是全局的,那么在头中声明它们,并在相应的模块中定义它们,特别是针对这些常量。

你可以混合和匹配这些不同的常量,它们具有不同的全局级别,你希望它们具有多大的全局性,以及不同的全局常量,它们根本不属于一起ーー如果你愿意,你可以把它们放在单独的模块中,每个模块都有自己的头部。

为什么不是 #define

过去的答案是“宏没有类型信息”,但是现在的编译器在对文字(宏可以扩展到什么)和变量进行类型检查方面非常聪明。

现代的答案是因为调试器不知道宏的存在。如果 MyThingNotificationKey是宏,则不能在调试器命令中说 [myThing addObserver:self forKey:MyThingNotificationKey]; 调试器只有在它是变量时才能知道它。

为什么不是 enum

好吧,rmaddy 在评论中打败了我: enum只能定义整数常量。比如序列标识号,位掩码,四字节码等等。

出于这些目的,enum非常棒,您绝对应该使用它。(更好的方法是使用 ABC1和 NS_OPTIONS。)对于其他事情,必须的使用其他东西; enum只做整数。

还有其他问题

我在考虑把文件导入到 Reddit-Prefix 中。Pch 文件,使所有文件都可以使用这些常量。这样做好吗?

可能无害,但可能过度。导入您需要的常量标头。

每个解决方案的用例是什么?

  • #define: 非常有限。说实话,我不确定是否有好的理由再把它用于常量。
  • const: 最适合局部常量。此外,您还必须对在头中声明并正在定义的元素使用此方法。
  • static const: 最适合特定于文件(或特定于类)的常量。
  • extern const: 在导出标头中的常量时必须使用此选项。

另外,如果使用 extern const,我是否需要导入文件,或者常量将在不导入文件的情况下全局可用?

您需要导入该文件,无论是在您使用它的每个文件中,还是在前缀头中。

基金会 _ 出口

考虑使用 FOUNDATION_EXPORTextern兼容性更强一些,因为它是在基础中定义的,并且可以编译成 C、 C + + 和 Win32的兼容格式。

正如在 NSObjecCRuntime.h 中定义的

#if defined(__cplusplus)
#define FOUNDATION_EXTERN extern "C"
#else
#define FOUNDATION_EXTERN extern
#endif


#if TARGET_OS_WIN32


#if defined(NSBUILDINGFOUNDATION)
#define FOUNDATION_EXPORT FOUNDATION_EXTERN __declspec(dllexport)
#else
#define FOUNDATION_EXPORT FOUNDATION_EXTERN __declspec(dllimport)
#endif


#define FOUNDATION_IMPORT FOUNDATION_EXTERN __declspec(dllimport)


#else
#define FOUNDATION_EXPORT  FOUNDATION_EXTERN
#define FOUNDATION_IMPORT FOUNDATION_EXTERN
#endif