为字符串常量妖魔化的 Objective-C #define 指令
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1977489/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Objective-C #define directive demonized for String constants
提问by GuidoMB
I've reading in several post and in Apple's code guidelines that in Objective-C String constants should be defined as extern NSString *const MY_CONSTANT;and that the #define directive should be avoided. Why is that? I know that #defineis run at precompile time but all string will share the same memory address. The only advantage I read was that if the constant must be updated or changed you don't have to recompile your entire project. So that i s the reason why #define should be avoided?
我在几篇文章和 Apple 的代码指南中读到过,Objective-C 中的字符串常量应该定义为 extern,NSString *const MY_CONSTANT;并且应该避免使用 #define 指令。这是为什么?我知道它#define在预编译时运行,但所有字符串都将共享相同的内存地址。我读到的唯一优点是,如果必须更新或更改常量,则不必重新编译整个项目。所以这就是为什么应该避免 #define 的原因?
Thanks
谢谢
UPDATE:In this case is good to use a #define or there is a better approach?
更新:在这种情况下最好使用 #define 还是有更好的方法?
/* Constants Definition */
#define SERVER_URL @"http://subdomain.domain.edu.ar/Folder/"
NSString *const ServerURL = SERVER_URL;
NSString *const LoginURL = SERVER_URL@"welcome.asp";
NSString *const CommandURL = SERVER_URL@"com.asp";
回答by e.James
A practical reason to use the constant as opposed to the definition is that you can do direct comparisons (using ==) instead of using isEqual:. Consider:
使用常量而不是定义的一个实际原因是您可以进行直接比较(使用 ==)而不是使用isEqual:。考虑:
NSString * const kSomeStringConstant = @"LongStringConstantIsLong";
...
[someArray addObject:kSomeStringConstant];
if ([someArray lastObject] == kSomeStringConstant)
{
...
}
This would work, since the ==comparison would be comparing identical const pointers to a single NSStringobject. Using #define, however:
这会起作用,因为==比较会将相同的 const 指针与单个NSString对象进行比较。使用#define,但是:
#define STRING_CONSTANT @"MacrosCanBeEvil";
...
[SomeArray addObject:STRING_CONSTANT]; // a new const `NSString` is created
if ([someArray lastObject] == STRING_CONSTANT) // and another one, here.
{
...
}
This would notwork out, since the two strings would have unique pointers. To compare them effectively, you would have to do a character-by-character comparison using isEqual:
这将不工作了,因为这两个字符串就具有独特的指针。为了有效地比较它们,您必须使用逐个字符进行比较isEqual:
if ([[someArray lastObject] isEqual:STRING_CONSTANT])
{
...
}
This can be far more costly in terms of execution time than the simple ==comparison.
与简单==比较相比,这在执行时间方面的成本可能要高得多。
Another motivation could be the size of the executable itself. The #defined constant would actually appear, in place, wherever it was used in the code. This could mean that the string appears many times in your executable. In contrast, the constant should (with modern compilers) be defined only once, and all further usages would make reference to the pointer to that one definition.
另一个动机可能是可执行文件本身的大小。#defined 常量实际上会出现在代码中使用它的任何地方。这可能意味着该字符串在您的可执行文件中出现多次。相比之下,常量(使用现代编译器)应该只定义一次,并且所有进一步的用法都将引用指向该定义的指针。
Now, before anyone yells at me for premature optimization, consider that the two approaches are almost identical in terms of implementation, but the const pointer method is far superior in terms of code size and execution time.
现在,在有人骂我过早优化之前,请考虑一下这两种方法在实现方面几乎相同,但是 const 指针方法在代码大小和执行时间方面要优越得多。
回答by Chuck
It's not necessarily guaranteed that there will only be one NXConstantString object for a given string literal in an entire application. It seems pretty likely that different compilation units might have different objects for the same constant string. For example, if somebody writes a plugin, one constant string will be generated for occurrences of that NSString literal in the plugin and one will be generated for occurrences in the host application, and these will not be pointer-equal.
不一定保证在整个应用程序中对于给定的字符串文字只有一个 NXConstantString 对象。对于同一个常量字符串,不同的编译单元很可能有不同的对象。例如,如果有人编写了一个插件,那么会为插件中 NSString 文字的出现生成一个常量字符串,并为宿主应用程序中的出现生成一个常量字符串,这些字符串不会是指针相等的。
回答by Michael
The best argument I have heard is that conststrings show up in the debugger, whereas macros do not.
我听到的最好的论点是const调试器中会显示字符串,而宏则不会。
回答by Dipu Rajak
static NSString * const SERVER_URL = @"http://subdomain.domain.edu.ar/Folder/";
回答by Asher Dunn
As far as I know, #defineonly lets you define C-style string constants. To create a constant NSString object, you have to declare it in the header, and then give it a value in one of your .m files.
据我所知,#define只允许你定义 C 风格的字符串常量。要创建一个常量 NSString 对象,你必须在头文件中声明它,然后在你的 .m 文件之一中给它一个值。
Header file:
头文件:
extern NSString *MyConstantString;
extern NSString *MyConstantString;
Main file:
主文件:
NSString *MyConstantString = @"String value";
NSString *MyConstantString = @"String value";

