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

Rob*_*udi 154 constants objective-c

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

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

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

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

我可以在逻辑上得出结论的一点enum是,在定义类似自定义错误域的东西时,这是最好的选择(我实际上是对吗?).但其他人呢?

Pet*_*sey 384

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

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

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

static NSString *const MyThingNotificationKey = @"MyThingNotificationKey";
Run Code Online (Sandbox Code Playgroud)

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

//.h
extern NSString *const MyThingNotificationKey;

//.m
NSString *const MyThingNotificationKey = @"MyThingNotificationKey";
Run Code Online (Sandbox Code Playgroud)

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

你可以为不同的常量混合和匹配这些常量,它们具有不同级别的全局性,以及不同的全局常量 - 你可以将它们放在单独的模块中,每个模块都有自己的标题,如果你想.

为什么不#define呢?

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

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

为什么不enum呢?

好吧,rmaddy在评论中打败了我:enum只能定义整数常量.串行标识符号,位掩码,四字节代码等等.

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

和其他问题

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

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

每种解决方案的用例有哪些?

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

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

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

  • 为什么不在`.h`文件中一共使用`static NSString*const`? (3认同)
  • @IulianOnofrei:如果它在应用程序而不是框架中,您可以.如果你执行`static NSString*const foo = @"foo";`,那么你的标题确定字符串是什么,并且它必须在任何地方相同 - 如果你改变字符串并且不同的各方使用不同版本的标题一个不同的字符串,然后字符串在运行时将不匹配.在框架中,您只想提供对符号的访问,并让框架成为该符号真实值的唯一来源,因此每个人都从一个地方获得相同的字符串.这就是`extern`给你的东西. (3认同)

Ste*_*ser 8

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
Run Code Online (Sandbox Code Playgroud)