在Objective-C中,我的理解是指令@“foo”定义了一个常量NSString。如果我在多个地方使用@“foo”,则会引用相同的不可变NSString对象。
为什么我经常看到这段代码片段(例如在UITableViewCell重用中):
static NSString *CellId = @"CellId";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellId];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:style reuseIdentifier:CellId];
而不仅仅是:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CellId"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:style reuseIdentifier:@"CellId"];
我认为这是为了保护我不会在编译器无法捕获的标识符名称中输入拼写错误。但如果是这样,我不能只是:
#define kCellId @"CellId"
并避免静态NSString *位?或者我错过了什么?
答案 0 :(得分:58)
将文字转换为常量是一种很好的做法,因为:
我更喜欢使用 static const NSString*
static NSString* const
,因为它比#define
稍微安全一些。我倾向于避免使用预处理器,除非我真的需要它。
答案 1 :(得分:36)
我喜欢这里的所有答案,而没有一个如何正确宣布一个......的简单例子......
如果你想让常量在外部可见(即“全局”)....在标题中声明它...
extern NSString *const MyTypoProneString;
并在.m
文件中定义, OUTSIDE 任何@implementation
类似...
NSString * const MyTypoProneString = @"iDoNtKnOwHoW2tYpE";
那就是说......如果你只想要一个static const
IS LOCAL 到你的班级实现(甚至是某种方法!)。只需将字符串 INSIDE 实现(或方法)声明为...
static NSString *MavisBeacon = @"She's a freakin' idiot";
编辑虽然我确实展示了如何执行此操作 ...我还没有确信这种风格以任何方式更好而不是更简洁,更简单,更少重复的单一宣言,ála..
#define SomeStupidString @"DefiningConstantsTwiceIsForIdiots"
使用#define
的...它们不那么烦人了......只是不要让预处理程序 - 玩家仇恨让你失望。
答案 2 :(得分:9)
答案 3 :(得分:3)
无法保证在多个位置使用@"foo"
时,运行时为它们使用相同的存储,当然可能不是编译单元或库边界的情况。
我宁愿使用static NSString *string = @"foo"
,特别是有很多文字字符串。
答案 4 :(得分:2)
我认为这是为了保护我不会在编译器无法捕获的标识符名称中输入拼写错误。
正确。这只是基本的防守编程实践。编译结果(希望如此)是相同的。
但如果是这样,我不能只是:
#define kCellId @"CellId"
并避免静态NSString *位?或者我错过了什么?
是。但kCellId
符号将全局定义,至少在您的编译单元中。声明一个静态变量会使该符号成为该块的本地符号。
通常会将字符串常量定义为全局变量或静态变量,而不是预处理器定义。这有助于确保您只处理不同编译单元之间的单个字符串实例。
答案 5 :(得分:1)
所以,我进入这个有点晚了,但是在SO的C / C ++领域已经多次以各种方式询问过这个问题,但基本上这是我对alex gray的评论的扩展版本:
任何时候你认为你应该为字符串宏使用#define,你很可能不应该这样做。原因是#define宏基本上是预处理器的正则表达式替换。只要预处理器看到一个被调用的宏,它就会用你定义的任何内容替换它。这意味着 new 字符串文字每次都会被分配到内存中,这在像单元格重用标识符这样的地方非常糟糕(因此Apple的UITableViewController默认代码使用静态代码)。
使用extern / static const代替将所有引用指向内存中的单个位置,如Eonil所述。这样可以提高内存效率和性能,这在移动设备上非常重要。