Reputation: 185
I want to make some NSNumber constants via the same style used for NSStrings in this topic. That is, I'm creating separate constants.h/.m files and importing them into classes that need to access them.
Upvotes: 18
Views: 11976
Reputation: 16022
Years later, I just realized it is possible to create a NSNumber constant for integers... but it's a hack:
#define CONST_INT_NSNUMBER( x ) ((__bridge NSNumber * const)(void * const)(( x << 8 ) | 0x27))
NSNumber * const number = CONST_INT_NSNUMBER(123) ;
This works because certain integer NSNumbers are stored as tagged pointers.
You can't do it.
NSNumber * const mynumber = @5.5;
gives:
Initializer element is not a compile-time constant
Implying the compiler has a special feature specifically for creating compile-time constant NSString
objects, but not any other type of object.
You could do this, however:
.h:
extern NSNumber * kConstantNumber ;
.m:
NSNumber * kConstantNumber ;
@implementation NSNumber (InitializeConstants)
+(void)load
{
kConstantNumber = @42;
// ... and the rest ...
}
@end
Upvotes: 5
Reputation: 41622
You can basically achieve close to what you want in three parts:
.h file:
extern NSNumber *MyFirstConstant;
.m file
NSNumber *MyFirstConstant;
AppDelegate.m
+(void)initialize
{
MyFirstConstant = @5;
...
}
AppDelegate is guaranteed to run before any of your other code, and the initialize is the first method that would be called on AppDelegate, so you can essentially insure all your constants are setup for you before your app runs.
Upvotes: 5
Reputation: 237010
The trouble with doing this is that there isn't such a thing as a compile-time constant NSNumber. Only NSString gets that distinction. NSNumbers are always created dynamically. You can fake it by using a function that runs at your program's startup to initialize the variables. Your options:
Create a class with a +load
method that performs the initialization.
In the file with the constants, include a function with __attribute__((constructor))
. So, for example:
// Constants.m
NSNumber *someGlobalNumber;
__attribute__((constructor))
static void InitGlobalNumber() {
someGlobalNumber = [[NSNumber numberWithInteger:1] retain];
}
But of course then you can't reliably use these numbers in any other functions which are run that early in the startup process. This usually isn't a problem, but is worth keeping in mind.
The other option, which I've seen crop up a few times, is to have a class with accessors for the numbers instead of giving raw access to the variables. It's a bit of a heavier design, but it also feels less voodooish, which has its charms.
Upvotes: 18
Reputation: 8488
Unfortunately you cannot currently generate NSNumber
constants in the same way you can generate NSString
constants. When you try to do you will get a compiler error
NSNumber * const kNumberConstant = @2; // This doesn't work.
However, you can use primitives instead.
NSInteger const kSomeIntValue = 10;
Upvotes: 16