32

I'm attempting to create an NSArray with a grouping of string literals, however I get the compile error "Initializer element is not constant".

NSArray *currencies = [NSArray arrayWithObjects:@"Dollar", @"Euro", @"Pound", nil];

Could someone point out what I'm doing wrong, and possibly explain the error message?

Kyle
  • 1,662
  • 2
  • 21
  • 38

6 Answers6

76

New syntax for creating an array with string literals:

NSArray *currencies = @[@"Dollar", @"Euro", @"Pound"];

To fix your complication error the code must be in a method. If you want to use it statically then create a class method that follows the singleton pattern.

malhal
  • 26,330
  • 7
  • 115
  • 133
  • Worth to notice it's going to be dynamically allocated array if it's inside of the method. I expected it to be as static constant array. – pronebird Aug 08 '13 at 09:24
18

This isn't a problem with the NSArray creation itself (you would get the same error if you wrote [NSArray array] instead), but with where you've written it. I'm guessing this is a global or file-static NSArray. In C, that kind of variable has to have a constant initializer — meaning not a function call (or, by extension, a method call). The solution is to put the actual creation and assignment of the array into a method that will be called before you need the array, such as initialize.

Chuck
  • 234,037
  • 30
  • 302
  • 389
7

It sounds like Chuck has spotted the problem. One thing you want to be aware of though in coding your solution is that you'll want to avoid storing an autoreleased instance of NSArray in a static variable. Also, a common pattern for these situations is to write a class method that creates and returns the value stored in the static variable, like so:

+ (NSArray *)currencies
{
    static NSArray *_currencies;

    // This will only be true the first time the method is called...
    //
    if (_currencies == nil)
    {
        _currencies = [[NSArray alloc] initWithObjects:@"Dollar", @"Euro", @"Pound", nil];
    }

    return _currencies;
}
jlehr
  • 15,557
  • 5
  • 43
  • 45
  • Hi, why is it not recommended to store autoreleased objects in static variables? Is it for efficiency so that they are not asked their retain count on every loop? – the Reverend Apr 22 '11 at 21:13
  • 1
    Objects in an autorelease pool aren't asked for their retain count; they're sent a `release` message when the autorelease pool is released. If an autoreleased object is stored in a static variable, the variable will contain an invalid address once this happens, and attempts to reference it will either crash your program, or even worse, cause it to incorrectly access some newer object that's been allocated at that address in the interim. – jlehr Apr 24 '11 at 14:45
  • Yes this is true, the docs also state that if you retain an autorelease object, your object will not be deallocated when the pool gets drained. If you use appkit an autorelease pool will be created on each event loop and drained at the end of it. So I think it does call retain count. – the Reverend Apr 28 '11 at 03:15
3

Although this is old, please notice that Apple committed a new patch to the llvm project adding support for new Objective-C literal syntax for NSArray, NSDictionary and NSNumber.

See here and here

Community
  • 1
  • 1
microspino
  • 7,693
  • 3
  • 48
  • 49
2

I'm a newbie in objective-c, but I think that the correct code is:

NSArray *currencies = [[NSArray alloc] initWithObjects:@"Dollar", @"Euro", @"Pound", nil];

I am not sure tho.

Adirael
  • 9,398
  • 2
  • 22
  • 15
  • 2
    That is also valid, however there is nothing wrong with OP's code. Your method simply retains the array whereas his does not – pheelicks May 06 '10 at 16:57
  • However, if the object stored in a static variable is **not** retained, it's a lurking crasher bug, so alloc/init would be the right thing to do. – jlehr May 06 '10 at 20:34
0

There's nothing wrong with that code. Are you sure the error is being produced at that line?

Dave DeLong
  • 242,470
  • 58
  • 448
  • 498