1

In my app I refer to a number of the same string variables from lots of different view controllers and I have created a number of global NSStrings using this method:

OpeningController.h (before @interface)

extern NSString *stringName;

OpeningController.m (after the @interface { } @end)

NSString *stringName =@"On";

I can then refer to/alter stringName anywhere in my application.

I want to be able to do the same with an array of strings but when I try the following I get the error Initializer is not a compile-time constant.

How do I achieve what I am trying to achieve?

OpeningController.h

extern NSArray *arrayName;

OpeningController.m (after the @interface { } @end)

NSArray *arrayName = [NSArray arrayWithObjects:
                     @"String1",
                     @"String2",
                     @"String3",
                     @"String4",
                     nil];
RGriffiths
  • 5,722
  • 18
  • 72
  • 120

3 Answers3

2

Assuming openingController is a class name (hint: it should be OpeningController) then you can initialize the array within the class's +initialize method, which will be invoked as soon as the class is referenced at runtime:

OpeningController.m:

#import "OpeningController.h"

NSArray *arrayName = nil;

@implementation OpeningController

+ (void)initialize {
    arrayName = [NSArray arrayWithObjects:
                @"String1",
                @"String2",
                @"String3",
                @"String4",
                nil];
}

....

@end

EDIT: Note that this isn't a particularly good example as referencing the array without referencing OpeningController first will access the un-initialized array. A better approach is a singleton pattern:

OpeningController.h:

@interface OpeningController : UIViewController  // Not sure of the subclass

+ (NSArray *)array;

...

@end

OpeningController.m:

#import "OpeningController.h"

@implementation OpeningController

+ (NSArray *)array {
    static NSArray *array = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        array = [NSArray arrayWithObjects:
                @"String1",
                @"String2",
                @"String3",
                @"String4",
                nil];
    });
    return array;
}

...

@end
trojanfoe
  • 120,358
  • 21
  • 212
  • 242
  • Thanks for the help. I have tried this but when I do NSLog(@"Array text - %@", [arrayName objectAtIndex:0]); from a different controller than the OpeningController it says the array is an undeclared identifier. – RGriffiths Jan 21 '14 at 16:41
  • @RichardGriffiths Yeah `+initialize` won't fire until `OpeningController` is referenced in code. It sounds like you might want to use a singleton pattern, so you can do `NSArray *array = [ObjectController array];`. See this article: http://www.galloway.me.uk/tutorials/singleton-classes/ – trojanfoe Jan 21 '14 at 20:02
  • @RichardGriffiths I've updated my answer with a singleton example. – trojanfoe Jan 21 '14 at 20:16
  • Thanks for the time you have gone to. I am really struggling to get past the + (NSArray)array; line which causes the error "Interface type 'NSArray' cannot be returned by value" when outside of the {} or "Expected ';' at end of declaration list" when inside the {}. – RGriffiths Jan 21 '14 at 22:37
  • @RichardGriffiths Arrrrg! That's cos it should be `NSArray *`! Fixing now. – trojanfoe Jan 22 '14 at 06:42
  • Thanks again. I have got this far and all is fine but I am not sure how to then reference the array. NSLog(@"%@", [array objectAtIndex:0]); gives me the error 'Use of undeclared identifier array' – RGriffiths Jan 22 '14 at 10:29
  • @RichardGriffiths The array is exposed via the "singleton accessor" (not an offical term), so: `NSLog(@"%@", [[OpeningController array] objectAtIndex:0]);` is what you want. – trojanfoe Jan 22 '14 at 10:38
  • Slowly slowly getting there. I have it now so that it works when I put NSLog(@"%@", [[OpeningController array] objectAtIndex:0]); in the OpeningController onLoad but if I put it in any other class it gives the error 'No known class method for selector array' – RGriffiths Jan 22 '14 at 11:47
  • @RichardGriffiths And you `#import "OpeningController.h"` in the other class's implementation file? – trojanfoe Jan 22 '14 at 11:48
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/45794/discussion-between-richard-griffiths-and-trojanfoe) – RGriffiths Jan 22 '14 at 11:51
1

Don't use shared global variables. They create very strong coupling between your different classes, and force all sorts of interdependencies. That leads very quickly to spaghetti-code.

Instead, create a data container singleton. That is a singleton object (do a google search on the singleton design pattern in Objective C, or even search here) that contain properties that you want to share.

Then any time you want to read or write a global variable, you use your singleton's accessor method to fetch the singleton and then invoke the desired property.

NSUserDefaults is an example of a singleton in Apple's frameworks. The code

[NSUserDefaults sharedUserDefaults] is a class method call that returns a pointer to the user defaults singleton.

Your code might look something like [MyDataSingleton sharedDataSingleton].

Duncan C
  • 128,072
  • 22
  • 173
  • 272
  • Thanks Duncan - I have been reading the debate at the bottom of the Matt Galloway article on singletons and there seems to be some question over the method. I am totally new to this so know nothing but wondered if there were any problems with doing it this way. – RGriffiths Jan 22 '14 at 08:23
0

You mus init the array, otherwise it will not work.

You can create a instance of the class and get that instance everytime you want.

If you have questions please tell me :)

Miguel Chaves
  • 139
  • 1
  • 9