我宣布:
static NSString *a = @"a";
这是iOS6中的正确声明(使用编译器版本应该更正确,但目前我还不知道)。我还想到了数字文字:
static NSNumber *b=@1;
可能是有效的声明。编译器告诉我initializer element is not a compile time constant
。这让我感到惊讶。由于NSNumber
不可变为NSString
,并且由于我在字符串情况下使用文字,因此我认为它也可以是有效的。
有没有人对这种差异有合理的解释?
答案 0 :(得分:17)
第一行是编译时常量,因为你分配@"a"
而不是像static NSString *a = [NSString stringWithFormat:@"a"];
那样(这会抛出相同的错误)
但对于NSNumber
,static NSNumber *b = @1;
实际上等同于static NSNumber *b = [NSNumber numberWithInt:1];
。有关详细信息check Objective-C Literals.
请注意,在上述情况下,右侧不是编译时常量。它是一个必须在运行时计算的表达式。在C和Objective-C中,必须使用编译时常量初始化静态变量。
如果您想NSNumber
作为const
,可以查看此处提到的方法Objective C - How to use extern variables?。
另外check this on Objective C literals from Mike Ash,
重要的是要注意,没有新的文字语法符合条件 作为编译时常量。
和
NSString文字也是编译时常量,因为它很紧 编译器和库之间的耦合。有一个特别的 NSString子类名为NSConstantString,具有固定的ivar布局:
这种紧密耦合具有优势,例如产生合法的全球性 变量初始化器,并且不需要运行额外的代码来构建 对象在运行时。但是,也存在很大的缺点。该 NSConstantString布局永远设置。必须保持这一课程 正是这种数据布局,因为数据布局被烘焙成 成千上万的第三方应用程序。如果Apple改变了布局,那些 第三方应用程序会破坏,因为它们包含NSConstantString 具有旧布局的对象。
如果NSArray文字是编译时常量,则需要 是一个类似的NSConstantArray类,具有固定的布局 编译器可以生成,并且必须维护 与其他NSArray实现分开。这样的代码无法运行 在没有此NSConstantArray类的旧操作系统上。相同 新文字可以存在的其他类存在问题 产生
在NSNumber文字的情况下,这一点特别有趣。 Lion引入了标记指针,允许NSNumber的内容 直接嵌入指针,无需a 分离动态分配的对象。如果编译器发出标记 指针,它们的格式永远不会改变,并且与旧的兼容性 操作系统版本将丢失。如果编译器发出恒定的NSNumber 对象,然后NSNumber文字将大不相同 其他NSNumbers,可能会有重大的性能影响。
相反,编译器只是向框架发出调用, 完全像手动完成的那样构造对象。 这会导致一点运行时命中,但不会比构建更糟糕 他们自己没有新的语法,并使一个更清洁 设计。