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.
4 Answers
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.

- 234,037
- 30
- 302
- 389
-
Best alternative answer so far. – Sep 04 '12 at 18:11
-
I prefer `__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. – bbum Sep 04 '12 at 18:12
-
@Chuck does this solution still work when automatic reference counting (ARC) is in use and calling `retain` is not allowed? – HairOfTheDog Mar 13 '13 at 23:24
-
@HairOfTheDog: ARC calls `retain` for you when assigning to `strong` variables, so yes, it should be fine AFAIK. – Chuck Mar 13 '13 at 23:27
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;

- 8,338
- 9
- 45
- 62
-
Of course because `NSString` constants are put into static memory, but `NSNumber` constants are autoreleased instances. Apple developers who created this are ... not very clever. – Sulthan Sep 04 '12 at 18:17
-
1@Sulthan: NXConstantString was not created by Apple developers AFAIK. It was already part of OpenStep. – Chuck Sep 04 '12 at 18:18
-
@Chuck Literal notation for `NSString` is fine. The new Obj-C additions (e.g. expression/number literals) are something a modern language should not have. – Sulthan Sep 04 '12 at 20:06
-
@Sulthan The source for both the Objective-C runtime and LLVM are available. If you have a better solution, implement it and submit a bug. Keep in mind that your solution needs to be compatible with millions of lines of code and needs to produce executable code that is backwards compatible across multiple years of releases and across several architectures. – bbum Sep 04 '12 at 20:59
-
@bbum You should read some books about code quality and what experienced programmers thing about new obj-c additions (e.g. teachers from Big Nerd Ranch). I don't want to say that something doesn't work (submit a bug), I want to say that the additions are stupid - even with a macro you can create better solutions doing the same but more readable. – Sulthan Sep 04 '12 at 22:00
-
1@Sulthan Um. Yeah. You might want to do a little more background research on bbum. My 2¢. – joshpaul Sep 04 '12 at 22:05
-
1@Sulthan: You just heard what an experienced Cocoa programmer thinks about the new Objective-C additions, dude. bbum is very experienced and ridiculously knowledgeable. The Big Nerd Ranch guys are awesome, but they don't speak for all experienced Cocoa programmers. And even all the Big Nerd Ranch guys don't think additions are "stupid" (I'm actually not aware that any of them have said so, but I know Mark Dalrymple at least said — and I quote — "I really like the new Objective-C literal syntax"). – Chuck Sep 04 '12 at 22:10
-
2It is a bit of to each his own; for a casual app, I go all in on the syntax (dot, subscripting, etc...). For my team's app, we have consciously decided to eschew dot syntax and array/dictionary subscripting, but are all in on the literal syntax and @property declarations. – bbum Sep 04 '12 at 22:28
-
@bbum:would you care to share your reasons for the eschewals? Consistency with existing codebase / Personal style preference are 2 possibilities I can think of, but interested if there's something else. – Cris Sep 05 '12 at 04:01
-
Personally, I'm on the fence, but lean to convenience when building relatively small, non performance sensitive, typical high level, app code. For large scale apps (like my team's), the ambiguity of *how much stuff might happen for that `.` 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. – bbum Sep 05 '12 at 05:52
-
@bbum:thanks. I would guess that the bulk of the code most of us write falls into the 1st category, in which case, I'm sure you're right that convenience (and I'd add readability) should reign. – Cris Sep 05 '12 at 10:52
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.

- 40,852
- 12
- 92
- 138
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

- 15,922
- 4
- 48
- 73
-
1One would hope that the compiler would at least warn that you're assigning an NSNumber to an NSString, even if it allowed that first expression. – Hot Licks Sep 04 '12 at 18:14
-
haha.. It did give a warning, but I only saw the error because that's what I was looking for. – nielsbot Sep 04 '12 at 18:19