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

时间:2013-06-21 05:35:28

标签: objective-c constants

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

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

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

另外,如果使用extern const,我是否需要导入文件,或者全局可以使用常量而不导入文件?

我可以在逻辑上得出结论,enum是定义类似自定义错误域的最佳选择(我实际上是对吗?)。但其他人呢?

2 个答案:

答案 0 :(得分:378)

第一个问题是你希望你的常数有多大的范围,这实际上是两个问题:

  • 这些常量是否特定于单个类,或者将它们全部放在应用程序上是否有意义?
  • 如果他们是特定于班级的,是否供班级客户使用,或仅在班级内使用?

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

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很棒,你绝对应该使用它。 (更好的是,使用the NS_ENUM and NS_OPTIONS macros。)对于其他事情,你必须使用其他东西; enum除了整数之外什么都不做。

和其他问题

  

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

可能无害,但可能过度。将常量标题导入到您需要的位置。

  

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

  • #define:相当有限。老实说,我不确定是否有充分的理由将其用于常数。
  • const:最适合本地常量。此外,您必须将此用于您在标题中声明的并且现在正在定义的那个。
  • static const:最适合特定于文件的(或类特定的)常量。
  • extern const:在标题中导出常量时必须使用此选项。
  

另外,如果使用extern const,我是否需要导入文件,或者全局可以使用常量而不导入文件?

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

答案 1 :(得分:8)

FOUNDATION_EXPORT

考虑使用FOUNDATION_EXPORTextern更具兼容性,因为它是在基础中定义的,并编译为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