我正在学习Objective-C和Cocoa并且遇到过这样的声明:

Cocoa框架期望全局字符串常量而不是字符串文字用于字典键,通知和异常名称,以及一些带字符串的方法参数。

我只使用更高级别的语言,所以从来没有必要考虑字符串的细节。 字符串常量和字符串文字之间有什么区别?

===============>>#1 票数:83 已采纳

在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最终可能会执行大量逐字节字符串比较。 如果大多数这些比较都被短路,因为被比较的字符串具有相同的指针,这可能是一个巨大的胜利。

===============>>#2 票数:12

一些定义

文字是一个值,根据定义是不可变的。 例如: 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 <object>被忽略, NSString实例( NSConstantString )已经是不可变的。

1关键字const适用于其左侧的任何内容。 如果它的左边没有任何东西,它适用于它右边的任何东西。

2这是运行时用于发送Objective-C中所有消息的函数,因此可用于更改对象状态的函数。

3示例:在const NSMutableArray *array = [NSMutableArray new]; [array removeAllObjects]; const NSMutableArray *array = [NSMutableArray new]; [array removeAllObjects]; const不会阻止最后一个语句。

4重写表达式的LLVM代码是RewriteModernObjC::RewriteObjCStringLiteral

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:的实现isEqualToString:比较哈希然后运行C函数strcmp ,因此它比直接比较指针要慢。 就是常量字符串更好的原因:它们比较快,不易出错。

如果您还希望常量字符串是全局的,请执行以下操作:

// header
extern NSString *const name;
// implementation
NSString *const name = @"john";

===============>>#3 票数:3

让我们使用C ++,因为我的Objective C完全不存在。

如果将字符串存入常量变量:

const std::string mystring = "my string";

现在当你调用方法时,你使用my_string,你正在使用一个字符串常量:

someMethod(mystring);

或者,您可以直接使用字符串文字调用这些方法:

someMethod("my string");

大概是,他们鼓励你使用字符串常量的原因是因为Objective C没有“实习”; 也就是说,当你在几个地方使用相同的字符串文字时,它实际上是指向字符串的单独副本的不同指针。

对于字典键,这会产生巨大的差异,因为如果我可以看到两个指针指向同一个东西,这比必须进行整个字符串比较要便宜得多,以确保字符串具有相同的值。

编辑: Mike,C#字符串是不可变的,具有相同值的文字字符串都指向相同的字符串值。 我想其他语言也是如此,它们具有不可变的字符串。 在具有可变字符串的Ruby中,它们提供了一种新的数据类型:符号(“foo”与:foo,前者是可变字符串,后者是常用于Hash键的不可变标识符)。

  ask by Benedict Cohen translate from so

未解决问题?本站智能推荐: