我正在学习Objective-C和Cocoa并且遇到过这样的声明:
Cocoa框架期望全局字符串常量而不是字符串文字用于字典键,通知和异常名称,以及一些带字符串的方法参数.
我只使用更高级别的语言,所以从来没有必要考虑字符串的细节.字符串常量和字符串文字之间有什么区别?
在Objective-C,语法@"foo"
是不可变的,文字的实例NSString
.它没有像Mike假设的那样从字符串文字中创建一个常量字符串.
Objective-C编译器通常在编译单元中执行实体文字字符串 - 也就是说,它们合并相同文字字符串的多次使用 - 并且链接器可以跨直接链接到单个二进制文件的编译单元执行其他实习.(由于Cocoa区分了可变字符串和不可变字符串,并且文字字符串始终也是不可变的,因此这可以是直接且安全的.)
另一方面,常量字符串通常使用如下语法声明和定义:
// MyExample.h - declaration, other code references this extern NSString * const MyExampleNotification; // MyExample.m - definition, compiled for other code to reference NSString * const MyExampleNotification = @"MyExampleNotification";
这里的语法练习的要点是,通过确保在同一地址空间中的多个框架(共享库)中只使用该字符串的一个实例,可以有效地利用字符串.(关键字的位置很重要;它保证指针本身保持不变.)const
虽然燃烧内存并不像25MHz 68030工作站那样拥有8MB内存,但是比较字符串是否需要时间.确保大多数时间相同的字符串也将是指针相等的帮助.
例如,假设您想按名称订阅来自对象的通知.如果对名称使用非常量字符串,则NSNotificationCenter
在确定对其感兴趣的人时,发布通知可能会进行大量逐字节字符串比较.如果大多数这些比较都被短路,因为被比较的字符串具有相同的指针,这可能是一个巨大的胜利.
甲文字是一个数值,它是由定义不可变的.例如:10
甲常数是只读变量或指针.例如:const int age = 10;
甲字符串文字就像是一个表达式@""
.编译器将用一个实例替换它NSString
.
一个字符串常量是只读指针NSString
.例如:NSString *const name = @"John";
关于最后一行的一些评论:
这是一个常量指针,而不是一个常量对象1.objc_sendMsg
2不关心你是否符合对象的资格const
.如果你想要一个不可变对象,你必须在对象3中编写不可变性.
所有@""
表达式都是不可变的.它们在编译时被替换为4个实例NSConstantString
,它是NSString
具有固定内存布局5的专用子类.这也解释了为什么NSString
在编译时可以初始化的唯一对象6.
甲常量字符串将是const NSString* name = @"John";
这相当于NSString const* name= @"John";
.这里,语法和程序员的意图都是错误的:const
被忽略,而NSString
instance(NSConstantString
)已经是不可变的.
1关键字const
apply适用于其左侧的任何内容.如果它的左边没有任何东西,它适用于它右边的任何东西.
2这是运行时用于发送Objective-C中所有消息的函数,因此可用于更改对象状态的函数.
3示例:在const NSMutableArray *array = [NSMutableArray new]; [array removeAllObjects];
const中不会阻止最后一个语句.
4重写表达式的LLVM代码RewriteModernObjC::RewriteObjCStringLiteral
位于RewriteModernObjC.cpp中.
5要查看NSConstantString
定义,cmd +在Xcode中单击它.
6为其他类创建编译时常量很容易,但需要编译器使用专门的子类.这会破坏与旧版Objective-C版本的兼容性.
Cocoa框架期望全局字符串常量而不是字符串文字用于字典键,通知和异常名称,以及一些带字符串的方法参数.当你有选择时,你应该总是喜欢字符串常量而不是字符串文字.通过使用字符串常量,您可以获得编译器的帮助来检查拼写,从而避免运行时错误.
它说文字很容易出错.但它并没有说它们也慢.相比:
// string literal [dic objectForKey:@"a"]; // string constant NSString *const a = @"a"; [dic objectForKey:a];
在第二种情况下,我使用带有const指针的键,所以相反[a isEqualToString:b]
,我可以这样做(a==b)
.执行isEqualToString:
比较哈希然后运行C函数strcmp
,因此它比直接比较指针慢.这就是常量字符串更好的原因:它们比较快,不易出错.
如果您还希望常量字符串是全局的,请执行以下操作:
// header extern NSString *const name; // implementation NSString *const name = @"john";