7

我声明:

static NSString *a = @"a";

这是iOS6中的正确声明(使用编译器版本应该更正确,但我目前不知道)。我认为数字文字也:

static NSNumber *b=@1;

可能是一个有效的声明。编译器告诉我initializer element is not a compile time constant。这让我有点吃惊。由于NSNumber是不可变的NSString,因为我使用的是字符串大小写的文字,我认为它也可能是有效的。

有人对这种差异有合理的解释吗?

4

1 回答 1

21

第一行是编译时常量,因为您正在分配@"a"而不是类似的东西static NSString *a = [NSString stringWithFormat:@"a"];(这将引发相同的错误)

但对于一个NSNumberstatic NSNumber *b = @1;其实就等价于static NSNumber *b = [NSNumber numberWithInt:1];。有关更多详细信息,请查看 Objective-C 文字。

请注意,在上述情况下,右侧不是编译时常量。它是一个必须在运行时计算的表达式。在 C 和 Objective-C 中,静态变量必须使用编译时常量进行初始化。

如果你想NSNumber作为一个const你可以检查这里提到的方法Objective C - How to use extern variables?.

还要检查来自 Mike Ash 的 Objective C 文字

重要的是要注意,新的文字语法都不能作为编译时常量。

和,

由于编译器和库之间的紧密耦合,NSString 文字也是编译时常量。有一个名为 NSConstantString 的特殊 NSString 子类,具有固定的 ivar 布局:

这种紧密耦合具有优势,例如生成合法的全局变量初始化器,并且不需要额外的代码来运行以在运行时构建对象。但是,也有很大的缺点。NSConstantString 布局是永久设置的。该类必须完全使用该数据布局来维护,因为该数据布局已融入数千个第三方应用程序。如果 Apple 更改布局,那些第三方应用程序就会崩溃,因为它们包含具有旧布局的 NSConstantString 对象。

如果 NSArray 字面量是编译时常量,则需要有一个类似的 NSConstantArray 类,它具有编译器可以生成的固定布局,并且必须与其他 NSArray 实现分开维护。这样的代码不能在没有这个 NSConstantArray 类的旧操作系统上运行。新文字可以产生的其他类也存在同样的问题。

这在 NSNumber 文字的情况下特别有趣。Lion 引入了标记指针,它允许将 NSNumber 的内容直接嵌入到指针中,从而无需单独的动态分配对象。如果编译器发出标记指针,它们的格式永远不会改变,并且与旧操作系统版本的兼容性将丢失。如果编译器发出常量 NSNumber 对象,那么 NSNumber 文字将与其他 NSNumber 有很大不同,可能会对性能造成重大影响。

相反,编译器只是简单地向框架发出调用,完全像您手动完成的那样构造对象。这会导致一些运行时问题,但并不比在没有新语法的情况下自己构建它们更糟糕,并且使设计更加简洁。

于 2012-12-14T02:03:16.753 回答