160

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

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

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

另外,如果使用extern const,我是否需要导入文件,或者常量将在全局范围内可用而无需导入文件?

我可以从逻辑上得出的结论是,enum在定义自定义错误域之类的内容时,这是最佳选择(我真的是对的吗?)。但是其他人呢?

4

2 回答 2

392

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

  • 这些常量是特定于单个类的,还是将它们遍布整个应用程序是否有意义?
  • 如果它们是特定于类的,它们是供类的客户使用的,还是只在类内使用?

如果它们是单个类的特定和内部的,请将它们声明为static const.m 文件的顶部,如下所示:

static NSString *const MyThingNotificationKey = @"MyThingNotificationKey";

如果它们属于单个类但应该是公共的/由其他类使用,extern请在标题中声明它们并在 .m 中定义它们:

//.h
extern NSString *const MyThingNotificationKey;

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

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

您可以将它们混合和匹配用于具有不同全局级别的不同常量,以及根本不属于一起的不同全局常量 - 您可以将它们放在单独的模块中,每个模块都有自己的标题,如果你想。

为什么不#define呢?

旧的答案是“宏没有类型信息”,但今天的编译器非常聪明地对文字(宏扩展为)以及变量进行所有类型检查。

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

为什么不enum呢?

好吧,rmaddy 在评论中击败了我:enum只能定义整数常量。诸如序列号、位掩码、四字节代码等之类的东西。

出于这些目的,enum它很棒,您绝对应该使用它。(更好的是,使用andNS_ENUMNS_OPTIONS)对于其他的东西,你必须使用其他的东西;enum除了整数之外什么都不做。

和其他问题

我正在考虑将文件导入 Reddit-Prefix.pch 文件以使常量可用于所有文件。这是做事的好方法吗?

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

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

  • #define: 相当有限。老实说,我不确定是否有充分的理由再将其用于常量。
  • const: 最适合局部常量。此外,您必须将其用于您在标题中声明并正在定义的内容。
  • static const: 最适合文件特定(或类特定)的常量。
  • extern const:在标头中导出常量时必须使用它。

另外,如果使用extern const,我是否需要导入文件,或者常量将在全局范围内可用而无需导入文件?

您需要在使用它的每个文件中或在前缀标头中导入该文件。

于 2013-06-21T05:51:14.430 回答
9

FOUNDATION_EXPORT

考虑使用FOUNDATION_EXPORT更多的兼容性,extern因为它在基础中定义并编译为 C、C++ 和 Win32 的兼容格式。

在 NSObjCRuntime.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
于 2015-08-26T20:33:51.960 回答