何时使用静态string与#define

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

static NSString *AppQuitGracefullyKey = @"AppQuitGracefully"; 

代替

 #define AppQuitGracefullyKey @"AppQuitGracefully" 

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

一个用法是:

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

或者这只是一个风格问题?

谢谢。

如果你使用静态的,编译器会在你的二进制文件中正好embedded一个string的副本,只是传递指向这个string的指针,导致更紧凑的二进制文件。 如果使用#define,每次使用时将在源中存储单独的string副本。 常量string合并将处理许多dups,但是你正在使连接器无故的工作。

请参阅“静态常量”与“#define”与“枚举” 。 static的主要优点是types安全。

除此之外,# #define方法引入了内联string连接的灵活性,不能用静态variables来完成,例如

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

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

在做了一些search之后( 这个问题/答案除外),我认为很重要的一点是,当你使用string@"AppQuitGracefully"常量string被创build的时候,无论你使用了多less次,它都会指向同一个对象。

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

我其实不会推荐,你应该使用extern来代替。 Objective-c已经定义了比extern 更便于携带的 FOUNDATION_EXPORT ,所以全局的NSString实例看起来像这样:

。H

 FOUNDATION_EXPORT NSString * const AppQuitGracefullyKey; 

.M

 NSString * const AppQuitGracefullyKey = @"AppQuitGracefully"; 

我通常把这些声明文件(如MyProjectDecl.h ),并在需要的时候导入。

这些方法有一些差异:

  • #define有几个缺点,比如不是types安全的。 确实有这样的解决方法(如#define ((int)1) )但是有什么意义呢? 而且,这种方法存在debugging缺点。 编译器更喜欢常量。 看到这个讨论。
  • 静态全局variables在声明的文件中是可见的。
  • extern使variables对所有文件都可见。 这与静态形成鲜明对比。

静态和外部的可见性不同。 还值得注意的是,这些方法都没有重复string(甚至没有#define ),因为编译器使用String Interning来防止这种情况。 在这NSHipsterpost他们显示certificate:

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

只有当两个variables指向相同的实例时,运算符==返回YES 。 正如你所看到的那样。

结论是:对全局常量使用FOUNDATION_EXPORT 。 这是debugging友好的,并将在整个项目中可见。

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

使用#define:

你不能debugging标识符的值

使用#define和其他macros是Pre-Processor的一个工作,当你先打开Build / Run,它将预处理源代码,它将与所有的macros(以符号#开始)一起工作,

假设你创build了,

 #define LanguageTypeEnglish @"en" 

并在你的代码中的2个地方使用它。

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

它将在所有地方用@"en"replace“LanguageTypeEnglish” 。 因此将会生成@"en"两个副本。 即

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

请记住,直到这个过程,编译器不在图片中。

编译器对所有的macros进行预处理后,进入画面,input代码如下,

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

并编译它。

使用静态:

它尊重范围,是types安全的。 你可以debugging标识符的值

在编译过程中如果发现编译器,

 static NSString *LanguageTypeRussian = @"ru"; 

那么它会检查以前是否存在同名的variables,如果是的话,它只会传递该variables的指针,如果不是,则会创build该variables并传递它的指针,下次只会传递指针一样。

所以使用静态,在范围内只生成一个variables副本。