1

I have a protocol class where I'm defining multiple String Constants and Array Constants containing these strings. I am porting over an android project.

In my Constants.h, I am declaring the NSString & NSArray constants as follows:

#imports.....

extern NSString *const constant1;
extern NSString *const constant2;

extern NSArray *const constantArr;

@protocol.....

Then in my Constants.m, I'm defining these constants:

#import "Constant.h"

NSString *const constant1 = @"Constant1";
NSString *const constant2 = @"Constant2";

//I get an error at this line
NSArray *const constantArr = [NSArray arrayWithObject: constant1, constant2, nil];

I get an error when defining the NSArray, it says Initializer element is not a compile-time constant. I believe I may be going about initialising the NSArray constant the wrong way.

Has anyone come across a similar issue or knows a way to initialise an NSArray Constant? Thanks

mhorgan
  • 886
  • 2
  • 11
  • 32
  • 3
    You can't use the `arrayWithObject` constructor, as that creates the array at runtime. You can create the array using the `@[constant1,constant2]` array literal syntax – Paulw11 Dec 16 '16 at 12:09
  • In both my .h and .m, i have tried `NSArray *const constantArr = @[constant1, constant2];` and I still get the same error. – mhorgan Dec 16 '16 at 12:15
  • You will need to be put the `@"Comstant1"` and `@"Constant2"` strings rather than using the variables in the array definition – Paulw11 Dec 16 '16 at 12:17
  • Just tried `NSArray *const constantArr = @[@"Constant1", @"Constant2"];` and I'm still getting the same error. I must be doing something stupid? – mhorgan Dec 16 '16 at 12:23
  • After a bit more research, you can't create constant Objective-C objects through this sort of initialiser. You will need to create the array as a property of some object in that objects initialiser. – Paulw11 Dec 16 '16 at 12:35
  • Sorry for the stupid question, but would you have some sample code for that? – mhorgan Dec 16 '16 at 12:37

1 Answers1

1

The problem is that you are trying to use runtime features at compile time, like instantiating an array (both [NSArray arrayWithObjects:] and the literal form @[] resolve to runtime allocations).

Constant strings don't suffer from this, as the compiler can allocate the bytes needed by the string in the data segment of the binary, however array's can't do this.

What you need is a piece of code that will execute when your application will be launched, and thus will be able to access runtime features.

The good news is that you can achieve this via the __attribute__((constructor)) modifier which tells the compiler to execute the decorated function when the binary is loaded, which coincidentally or not is when the app starts, before any AppDelegate code executes.

NSArray *constantAr;

//...

__attribute__((constructor))
static void initialize_constants() {
    constantArr = @[constant1, constant2];
}

The downside is that you will need to give up the const modifier, thus the array will no longer be a true constant.

Cristik
  • 30,989
  • 25
  • 91
  • 127
  • Thanks very much for the clear answer. Makes sense in my head and I'll have to integrate this method. I can give up the true constant. – mhorgan Dec 19 '16 at 10:01