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.
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.
__attribute__((constructor_))
over +load
because constructor
is both universal and very easy to search for across a whole codebase whereas searching for load
typically yields about a zillion unrelated hits. –
Oquassa retain
is not allowed? –
Teleutospore retain
for you when assigning to strong
variables, so yes, it should be fine AFAIK. –
Seth 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;
NSString
constants are put into static memory, but NSNumber
constants are autoreleased instances. Apple developers who created this are ... not very clever. –
Swish NSString
is fine. The new Obj-C additions (e.g. expression/number literals) are something a modern language should not have. –
Swish .
or that [...]
expression combined with the need to delve into code one might not have seen makes us lean to expressions that indicate exactly what is happening. –
Oquassa 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.
update:
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.
original answer:
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
© 2022 - 2024 — McMap. All rights reserved.