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

mah*_*udz 45 xcode cocoa cocoa-touch objective-c

关于什么时候最好使用我有点困惑:

static NSString *AppQuitGracefullyKey = @"AppQuitGracefully";
Run Code Online (Sandbox Code Playgroud)

代替

#define AppQuitGracefullyKey    @"AppQuitGracefully"
Run Code Online (Sandbox Code Playgroud)

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

一种用法是:

appQuitGracefully =  [[NSUserDefaults standardUserDefaults] integerForKey: AppQuitGracefullyKey];
Run Code Online (Sandbox Code Playgroud)

或者只是风格问题?

谢谢.

cde*_*osa 60

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

  • 常量字符串合并是编译器的工作,而不是链接器. (9认同)
  • @AndréFratelli事实上,常量字符串合并是一种链接器优化,它由OS X/macOS中的静态链接器实现,用于C和CF/NSStrings.它不是使用字符串实习完成的,并且它不是由编译器完成的(尽管编译器可能在写出其生成的目标文件之前合并字符串本身).您可以在[链接器源代码](http://opensource.apple.com/source/ld64/ld64-264.3.102/)中查看执行此操作的代码.所以不,肯尼特不对; 它确实是链接器. (2认同)

ken*_*ytm 14

请参阅"static const"vs"#define"vs"enum".主要优点static是类型安全.

除此之外,该#define方法引入了内联字符串连接的灵活性,这不能用静态变量来完成,例如

#define ROOT_PATH @"/System/Library/Frameworks"
[[NSBundle bundleWithPath:ROOT_PATH@"/UIKit.framework"] load];
Run Code Online (Sandbox Code Playgroud)

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

  • 我很惊讶.我不知道`@"一个字符串"@"另一个字符串"`是有效的. (34认同)

And*_*lli 5

我实际上不会推荐两者,你应该使用它extern。Objective-c 已经定义了FOUNDATION_EXPORT哪个比更便携extern,所以全局NSString实例看起来像这样:

。H

FOUNDATION_EXPORT NSString * const AppQuitGracefullyKey;
Run Code Online (Sandbox Code Playgroud)

.m

NSString * const AppQuitGracefullyKey = @"AppQuitGracefully";
Run Code Online (Sandbox Code Playgroud)

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

这些方法有一些不同之处:

  • #define有几个缺点,例如类型不安全。确实有解决方法(例如#define ((int)1)),但有什么意义呢?此外,这种方法还有调试缺点。编译器更喜欢常量。看到这个讨论。
  • 静态全局变量在它们声明的文件可见。
  • extern使变量对所有文件可见。这与静态形成对比。

静态和外部的可见性不同。还值得注意的是,这些方法都不会复制字符串(甚至不会#define),因为编译器使用String Interning来防止这种情况。在这篇 NSHipster 帖子中,他们展示了证据:

NSString *a = @"Hello";
NSString *b = @"Hello";
BOOL wtf = (a == b); // YES
Run Code Online (Sandbox Code Playgroud)

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

结论是:FOUNDATION_EXPORT用于全局常量。它是调试友好的,并且在您的整个项目中都是可见的。