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

Posted

技术标签:

【中文标题】在 Objective-C 中创建常量的最佳方法是啥【英文标题】:What is the best way to create constants in Objective-C在 Objective-C 中创建常量的最佳方法是什么 【发布时间】:2013-06-18 04:15:11 【问题描述】:

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

#defineconst static const extern const enum

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

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

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

【问题讨论】:

***.com/questions/11153156/… 请访问此链接...您的解决方案在此帖子中 @BhavikKama:这是一个相对于两个具体解决方案的狭隘问题。 for - static const, #define , enum ,这个链接很有用 ***.com/questions/1674032/static-const-vs-define-in-c 很好地解释了 const 的这 3 个替代方案 enum 仅对整数值有用。 #define 和常量可以是任何数据类型。 conststatic constextern const 除了范围之外都相同。所以真的只有三个选择。 【参考方案1】:

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

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

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

static NSString *const MyThingNotificationKey = @"MyThingNotificationKey";

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

//.h
extern NSString *const MyThingNotificationKey;

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

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

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

为什么不#define

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

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

为什么不enum

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

出于这些目的,enum 非常棒,您绝对应该使用它。 (更好的是,使用the NS_ENUM and NS_OPTIONS macros。)对于其他事情,您必须使用其他东西; enum 除了整数之外什么都不做。

及其他问题

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

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

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

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

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

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

【讨论】:

为什么不在.h 文件中完全使用static NSString *const @IulianOnofrei:如果它在应用程序而不是框架中,您可以。如果你使用static NSString *const foo = @"foo";,那么你的标题决定了字符串是什么,并且它必须在任何地方都相同——如果你改变了字符串并且不同的各方使用不同版本的标题和不同的字符串,那么字符串不会在运行时匹配。在框架中,您只想提供对符号的访问,并让框架成为该符号真实值的唯一来源,因此每个人都从一个地方获取相同的字符串。这就是extern 带给你的。 关于#defines 的附加说明:不能保证它们在内存中具有相同的地址(取决于它们的声明方式,它们可能会在每次使用时分配一个新实例) ,因此使用myObject == MyDefine 不会总是按预期工作,但myObject == MyStaticConst 会。 static NSString *const代替static NSString const*这样的拼写有意义吗?有什么不同吗?! @kokos8998 有什么不同吗?是的,它确实。 static NSString const *static const NSString * 相同,意思是“指向常量 NSString 的(可变)指针”——这在这里有点没用,因为 NSString 已经是不可变的。你想要的只是static NSString * const - 这是一个“指向 NSString 的常量指针”【参考方案2】:

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

【讨论】:

以上是关于在 Objective-C 中创建常量的最佳方法是啥的主要内容,如果未能解决你的问题,请参考以下文章

在 Objective-C 中创建私有属性

在 C++ 中创建全局“常量”的正确方法

使用 XCTest 在 Objective-C 静态库中创建测试用例

Objective-c 中局部常量的最佳实践

在 C# 中创建常量字典

在 ViewController 中创建选项卡视图的最佳方法是啥