14

how can i declare a global NSArray and then use it across my app?

user140736
  • 1,913
  • 9
  • 32
  • 53

6 Answers6

27

There are a couple different ways you can do this:

  1. Instead of declaring it as a global variable, wrap it in a singleton object, then have the singleton by available anywhere (by #importing the .h file)

  2. Create a .h file, like "Globals.h". In the .h, declare your array as extern NSMutableArray * myGlobalArray; Then in the somewhere else in your app (the AppDelegate is a good place), just do: myGlobalArray = [[NSMutableArray alloc] init]; Then anywhere you need the array, just #import "Globals.h"

  3. This is like #2, but without the global header. You can define your array as extern NSMutableArray *myGlobalArray; inside the #ifdef __OBJC__ block of your project's .pch file. The .pch file is a header file that is automatically #imported into every file in your project.

There are pros and cons of each approach. I've used all three at varying times in varying circumstances. I would say the singleton approach is probably the most proper, since it would be most flexible for initialization, access restriction, and memory management. However, it can be unnecessary if you don't need that.

Option #2 is nice if you have lots of "global" variables that you don't want to expose to every file across your project. You can just #import it where its needed. However, this approach (as well as #3) disassociates the declaration from the initialization (ie, the object is not created near where it's declared). Some might argue this is not proper, and they might be correct.

Option #3 is nice because then you never have to remember to #import anything at all. However, it raises the same questions as option #2.

Dave DeLong
  • 242,470
  • 58
  • 448
  • 498
  • Hi i have used the third option but when i use **static extern NSMutableArray * myGlobalArray;** it gives an error of **Multiple Storage classes in declaration specifier** – rptwsthi Apr 05 '11 at 11:06
  • 1
    @rptwsthi yeah sorry. Just remove the "static" bit. – Dave DeLong Apr 05 '11 at 14:19
  • last time I have been failed to achieve desired response from third way, but this time i did. Thank you for this nice post. :) – rptwsthi Oct 14 '11 at 09:15
  • 1
    i have used the Third Approach, I have NSString *global; varibale and in my Controller when i write global = @"data"; Then it gives me Symbol(s) not found error. Whats i am doing wrong. – Shah Jan 03 '12 at 11:35
  • if i close my application will this array contain the record ?? –  Apr 10 '13 at 13:37
  • I got an error in third option, Undefined symbols for architecture i386: "_myGlobalArray", referenced from: Please define how can I resolve it. – Prince Kumar Sharma Nov 27 '14 at 13:13
8

A 4th answer is to declare the array in your UIApplicationDelegate and access it through

[[[UIApplication sharedApplication] delegate] myArray];

For times when I just need a handful of global objects, I found this is the easiest and cleanest way to do it.

kubi
  • 48,104
  • 19
  • 94
  • 118
  • 6
    +1 This is also a good approach. The only caveat this has is that it'll produce a compiler warning, since -[UIApplication delegate] returns an object of type id, which does not have a "myArray" method. The solution would be to cast it, but that makes the line somewhat more difficult to ready: `[(MyAppDelegate *)[[UIApplication sharedApplication] delegate] myArray];` – Dave DeLong Aug 08 '09 at 16:36
  • 1
    Plus, casting it means you would also need to #import the MyAppDelegate header file. – Dave DeLong Aug 08 '09 at 16:37
  • I use Xcode 4.3. The situation you mentioned will force an error, not merely a warning. – Philip007 Aug 20 '12 at 13:44
  • Since this solution implicitly use getter method of myArray when access it, one must declare the array as @property in appDelegate.m (or .h) to make it work. Complete code sample is much more benefit than one line without comment, as least for newbies. – Philip007 Aug 20 '12 at 13:52
2

If you're considering storing some kind of shared preferences for your app, use [NSUserDefaults sharedDefaults] to persist simple data which can be used across app. If you're storing transient data, then the 'static' approach will work as elsewhere.

However it's probably better to use a singleton object approach with a class accessor, like NSUserDefaults, and then provide instance accessor methods to acquire your data. That way, you'll isolate yourself from potential data structure changes in the future. You'd then use a static var, as above, but within the .m file (and hence you don't need the 'extern' definition). It would typically look like:

static Foo *myDefault = nil;
@implementation Foo
+(Foo)defaultFoo {
  if(!myDefault)
    myDefault = [[Foo alloc] init]; // effective memory leak
  return myDefault;
}
@end

You'd then have instance accessors, and use them as [[Foo defaultFoo] myArray] which can be accessed from any part of the app, and without any compile time errors.

AlBlue
  • 23,254
  • 14
  • 71
  • 91
1

Everyone here seems to have an implicit, omitted first line: "You can do it K&R C-style, or..."

Yes, you can still do it C-style.

In file 1:

NSArray *MyArray;

In file 2:

extern NSArray *MyArray;

Playing Captain Obvious here.

Seva Alekseyev
  • 59,826
  • 25
  • 160
  • 281
  • 1
    It's not that obvious, I think it's fairly common for new-ish Obj-C developers to have no C experience. – kubi Apr 08 '11 at 10:49
1

In reference to Dave's answer here:

This is like #2, but without the global header. You can define your array as static extern NSMutableArray *myGlobalArray; inside the #ifdef OBJC block of your project's .pch file. The .pch file is a header file that is automatically #imported into every file in your project.

typedef is a storage class and static is a storage class, and you can only define objects in one storage class. Taking out "static" will allow the app to compile with your answer above.

Ethan Allen
  • 14,425
  • 24
  • 101
  • 194
0

There are several possibilities. Most popular:

1 Use singleton object - http://www.galloway.me.uk/tutorials/singleton-classes/

2 Declare it in app delegate:

@interface Your_App_Delegate : UIResponder <UIApplicationDelegate>

@property (nonatomic, strong) NSArray *array;
   . . .

and access it:

((Your_App_Delegate*)[[UIApplication sharedApplication] delegate]).array;

3 Use NSUserDefault

Avt
  • 16,927
  • 4
  • 52
  • 72