Objective c Obj-C中的NSN数常数

Objective c Obj-C中的NSN数常数,objective-c,ios,constants,nsnumber,Objective C,Ios,Constants,Nsnumber,我想通过中用于NSStrings的相同样式生成一些NSNumber常量。也就是说,我正在创建单独的常量.h/.m文件,并将它们导入需要访问它们的类中 不幸的是,您当前无法以与生成NSString常量相同的方式生成NSNumber常量。当你尝试这样做时,你会得到一个编译器错误 NSNumber * const kNumberConstant = @2; // This doesn't work. 但是,您可以改为使用基本体 NSInteger const kSomeIntValue = 10;

我想通过中用于NSStrings的相同样式生成一些NSNumber常量。也就是说,我正在创建单独的常量.h/.m文件,并将它们导入需要访问它们的类中

不幸的是,您当前无法以与生成
NSString
常量相同的方式生成
NSNumber
常量。当你尝试这样做时,你会得到一个编译器错误

NSNumber * const kNumberConstant = @2; // This doesn't work.
但是,您可以改为使用基本体

NSInteger const kSomeIntValue = 10;
更新: 几年后,我才意识到可以为整数创建一个NSNumber常量。。。但这是一个黑客:

#define CONST_INT_NSNUMBER( x ) ((__bridge NSNumber * const)(void * const)(( x << 8 ) | 0x27))


NSNumber * const number = CONST_INT_NSNUMBER(123) ;
给出:

初始值设定项元素不是编译时常量

这意味着编译器具有专门用于创建编译时常量
NSString
对象的特殊功能,而不是任何其他类型的对象

但是,您可以这样做:

.h

extern NSNumber * kConstantNumber ;
NSNumber * kConstantNumber ;

@implementation NSNumber (InitializeConstants)

+(void)load
{
    kConstantNumber = @42;
    // ... and the rest ...
}

@end
.m

extern NSNumber * kConstantNumber ;
NSNumber * kConstantNumber ;

@implementation NSNumber (InitializeConstants)

+(void)load
{
    kConstantNumber = @42;
    // ... and the rest ...
}

@end

这样做的问题是没有编译时常量NSNumber。只有NSString才有这种区别。NSN编号始终是动态创建的。您可以通过使用在程序启动时运行的函数来初始化变量来伪造它。您的选择:

  • 使用执行初始化的
    +load
    方法创建一个类

  • 在包含常量的文件中,包括一个具有
    \uuuu属性的函数((构造函数))
    。例如:

    // Constants.m
    
    NSNumber *someGlobalNumber;
    
    __attribute__((constructor))
    static void InitGlobalNumber() {
        someGlobalNumber = [[NSNumber numberWithInteger:1] retain];
    }
    
  • 但当然,在启动过程的早期运行的任何其他函数中,都不能可靠地使用这些数字。这通常不是问题,但值得记住


    另一个选项,我已经见过几次了,是有一个带有数字访问器的类,而不是提供对变量的原始访问。这是一个较重的设计,但它也感觉不到巫毒,这有它的魅力。

    你可以通过三个部分基本上达到你想要的:

    .h文件:

    extern NSNumber *MyFirstConstant;
    
    .m文件

    NSNumber *MyFirstConstant;
    
    AppDelegate.m

    +(void)initialize
    {
        MyFirstConstant = @5;
        ...
    }
    

    AppDelegate保证在任何其他代码之前运行,并且initialize是AppDelegate上调用的第一个方法,因此您可以基本上确保在应用程序运行之前为您设置所有常量。

    迄今为止的最佳备选答案。我更喜欢
    \uuuu attribute\uuuu((构造函数))
    over
    +load
    ,因为
    构造函数既通用又很容易在整个代码库中搜索,而搜索
    load
    通常会产生大量无关的点击。@Chuck在自动引用计数(ARC)时,此解决方案仍然有效吗正在使用并且不允许调用
    retain
    ?@hairofdog:ARC在分配给
    strong
    变量时为您调用
    retain
    ,所以是的,这应该很好。希望编译器至少会警告您正在将NSNumber分配给NSString,即使它允许第一个表达式。哈哈。。它确实发出了警告,但我只看到了错误,因为这正是我要查找的。当然,这是因为
    NSString
    常量被放入静态内存,但是
    NSNumber
    常量是自动删除的实例。创建这个的苹果开发者是。。。不是很聪明。@Sulthan:NXConstantString不是由苹果开发者AFAIK创建的。这已经是OpenStep的一部分了。@Sulthan Um。是 啊你可能想对bbum做更多的背景研究。我的2美分。@Sulthan:你刚刚听到一个有经验的Cocoa程序员对新添加的Objective-C的看法,伙计。bbum经验丰富,知识渊博。“大书呆子农场”的家伙真是太棒了,但他们并不是所有有经验的可可程序员的代言人。即使是所有的大怪人农场的家伙也不认为添加是“愚蠢的”(我实际上不知道他们中有人这么说,但我知道Mark Dallymple至少说过——我引述他的话——“我真的很喜欢新的Objective-C字面语法”)。这对每个人来说都有点不同;对于一个休闲应用程序,我会全力以赴地使用语法(点、订阅等)。对于我的团队的应用程序,我们已经有意识地决定避免点语法和数组/字典订阅,但都在使用文字语法和@property声明。