在 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 * 位?还是我错过了什么?
将文字转换为常量是一个很好的做法,因为:
我更喜欢使用
static NSString* const
,因为它比#define
稍微安全一些。我倾向于避免使用预处理器,除非我真的需要它。
我喜欢这里的所有答案,但没有一个简单的例子来说明如何正确声明一个......所以......
如果您希望常量外部可见(即“全局”)...在标头中如此声明...
extern NSString *const MyTypoProneString;
并在
.m
文件中定义它,OUTSIDE任何@implementation
,例如...
NSString * const MyTypoProneString = @"iDoNtKnOwHoW2tYpE";
也就是说...如果您只是想要一个
static const
IS LOCAL 到您的类的实现(甚至某个方法!)...只需声明字符串 INSIDE 实现(或方法)作为...
static NSString *MavisBeacon = @"She's a freakin' idiot";
编辑虽然我确实展示了如何做到这一点...我还没有确信这种风格在任何方面都比可笑的更短、更简单、更少重复的 SINGLE 声明更好,la..
#define SomeStupidString @"DefiningConstantsTwiceIsForIdiots"
使用
#define
...它们不那么烦人..只是不要让预处理器玩家讨厌者让你失望。
不能保证在多个地方使用
@"foo"
时,运行时会为它们使用相同的存储,并且当然可能不会跨编译单元或库边界出现这种情况。static NSString *string = @"foo"
,尤其是对于很多文字字符串。
我认为它是为了保护我免于在编译器无法捕获的标识符名称中犯下拼写错误。
正确。这只是基本的防御性编程实践。无论哪种方式,编译的结果(希望)都是相同的。
但是如果是这样,我难道不能:
#define kCellId @"CellId"
并避免静态 NSString * 位?还是我错过了什么?
是的。但是
kCellId
符号将是全局定义的,至少在你的编译单元中是这样。声明静态变量使符号成为该块的本地符号。
您通常会看到字符串常量定义为全局变量或静态变量,而不是预处理器定义。这有助于确保您只处理不同编译单元之间的单个字符串实例。
所以,我进入这个问题有点晚了,但是在 SO 的 C / C++ 领域已经以各种方式多次询问过这个问题,但基本上这是我对 alex Gray 的评论的扩展版本:
任何时候您认为应该对字符串宏使用#define,您很可能不应该这样做。原因是 #define 宏基本上是预处理器的正则表达式替换。每当预处理器看到调用的宏时,它就会用您定义的任何内容替换它。这意味着每次都会将一个new字符串文字分配到内存中,这在像单元重用标识符这样的地方非常糟糕(这就是为什么Apple的UITableViewController默认代码使用静态)。
使用 extern / static const 来代替将所有引用指向内存中的单个位置,正如 Eonil 提到的。这可以提高内存效率和性能,这对于移动设备非常重要。