何时使用静态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副本。