何时使用静态字符串与#define

时间:2010-01-19 08:12:40

标签: objective-c cocoa cocoa-touch xcode

关于何时最好使用,我有点困惑:

static NSString *AppQuitGracefullyKey = @"AppQuitGracefully";

而不是

#define AppQuitGracefullyKey    @"AppQuitGracefully"

我在C或C ++中看到过这样的问题,我认为这里的不同之处在于,这是针对Objective C的,利用对象,而在像iPhone这样的设备上,可能有堆栈,代码空间或记忆问题,我还没有掌握。

一种用法是:

appQuitGracefully =  [[NSUserDefaults standardUserDefaults] integerForKey: AppQuitGracefullyKey];

或者只是风格问题?

感谢。

6 个答案:

答案 0 :(得分:59)

如果使用静态,编译器将在二进制文件中只嵌入一个字符串副本,只是将指针传递给该字符串,从而产生更紧凑的二进制文件。如果使用#define,则每次使用时都会在源中存储单独的字符串副本。常量字符串合并将处理许多重复,但是您无需任何理由使链接器更加努力。

答案 1 :(得分:14)

"static const" vs "#define" vs "enum"static的主要优点是类型安全。

除此之外,#define方法引入了内联字符串连接的灵活性,这是静态变量无法实现的,例如。

#define ROOT_PATH @"/System/Library/Frameworks"
[[NSBundle bundleWithPath:ROOT_PATH@"/UIKit.framework"] load];

但这可能不是一个好的风格:)。

答案 2 :(得分:4)

在做了一些搜索(this问题/答案等)后,我认为重要的是要说当你使用字符串文字@"AppQuitGracefully"时,任何时候都会创建常量字符串,无论多少你使用它的次数会指向相同的对象。

所以我认为(如果我错了,我向我道歉)上述答案中的这句话是错误的:If you use a #define, there will be a separate copy of the string stored in the source on each use.

答案 3 :(得分:4)

我实际上不会推荐,你应该使用extern代替。 Objective-c已定义FOUNDATION_EXPORT more portable而不是extern,因此全局NSString实例看起来像这样:

·H

FOUNDATION_EXPORT NSString * const AppQuitGracefullyKey;

的.m

NSString * const AppQuitGracefullyKey = @"AppQuitGracefully";

我通常将它们放在声明文件(例如MyProjectDecl.h)中,并在需要时导入。

这些方法存在一些差异:

  • #define 有几个缺点,例如不是类型安全的。确实存在相关的解决方法(例如#define ((int)1)),但重点是什么?此外,该方法存在调试缺点。编译器更喜欢常量。请参阅this讨论。
  • 静态全局变量为visible in the file they are declared.
  • extern 使变量对所有文件可见。这与静电相反。

静态和外部的能见度不同。同样值得注意的是,这些方法都没有重复字符串(甚至不是#define),因为编译器使用String Interning来防止这种情况。在this NSHipster post中,他们会出示证据:

NSString *a = @"Hello";
NSString *b = @"Hello";
BOOL wtf = (a == b); // YES

只有当两个变量指向同一个实例时,运算符==才会返回YES。正如你所看到的,确实如此。

结论是:对全局常量使用FOUNDATION_EXPORT。它的调试友好,并且可以在整个项目中显示。

答案 4 :(得分:3)

当我需要从库或框架中导出NSString符号时,我使用static。当我在很多地方需要一个字符串时,我可以使用#define来轻松更改。无论如何,编译器和链接器将负责优化。

答案 5 :(得分:3)

使用#define:

您无法调试标识符

的值

使用#define和其他宏是预处理器的工作, 当你首先点击构建/运行它将预处理源代码,它将适用于所有的宏(从符号#开始),

假设您已创建,

#define LanguageTypeEnglish @"en"

并在代码中的2个位置使用它。

NSString *language = LanguageTypeEnglish;
NSString *languageCode = LanguageTypeEnglish;

它会在所有地方用@"en"替换“LanguageTypeEnglish”。 因此将生成2份@"en"副本。 即

NSString *language = @"en";
NSString *languageCode = @"en";

请记住,在此过程中,编译器不在图片中。

预处理完所有宏后,编译器出现在图片中,它会得到这样的输入代码,

NSString *language = @"en";
NSString *languageCode = @"en";

并编译它。

使用静态

它尊重范围并且是类型安全的。 你可以调试标识符的值

在编译过程中如果找到编译器,

static NSString *LanguageTypeRussian = @"ru";

然后它将检查先前存储的同名变量, 如果是,它只会传递该变量的指针, 如果不是,它将创建该变量并传递它的指针,下次它将只传递相同的指针。

因此,使用static,在范围内只生成一个变量副本。