How do I share an object between UIViewControllers on iPhone?

One option you have is to declare your date model as instance variables of your app delegate (as mentioned by other commenters).

Instead of referencing the app delegate as suggested by nevan an alternative is to add a property to your view controller classes (A and B) for your data model.

Say you wanted to share a data model object between your view controllers you can add a property to each:

@interface AViewController : UIViewController {
    MyDataModel *model;
}

@property (nonatomic, retain) MyDataModel *model;

@end

@interface BViewController : UIViewController {
    MyDataModel *model;
}

@property (nonatomic, retain) MyDataModel *model;

@end

When you initialise your view controller you can then set this property to the object context initialised previously.

You have mentioned a tab bar controller. If your view controllers are wired through IB all you have to do is to set these parameters in your application delegate applicationDidFinishLaunching: method, before the tab bar controller is displayed:

@interface MyAppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate>
{

    MyDataModel *model;
    AViewController *aViewController;
    BViewController *bViewController;
    ...
}

@property (retain) IBOutlet AViewController *aViewController;
@property (retain) IBOutlet BViewController *aViewController;

@end

@implementation MyAppDelegate

...

- (void)applicationDidFinishLaunching:(UIApplication *)application
{
...

    aViewController.model = model;

    bViewController.model = model;

    [window addSubview:tabBarController.view];
    [window makeKeyAndVisible];
}

Don't forget to release the model in your view controller's dealloc method.


The alternative is to use a singleton object. An simple singleton example:

@interface MyDataModel : NSObject
{
}

+ (MyDataModel *) sharedDataModel;

@end

@implementation MyDataModel

static MyDataModel *sharedDataModel = nil;

+ (MyDataModel *) sharedDataModel
{

    @synchronized(self)
    {
        if (sharedDataModel == nil)
        {
            sharedDataModel = [[MyDataModel alloc] init];
        }
    }
    return sharedDataModel;
}

@end

You can access this data model from all your view controllers with something similar to the following:

MyDataModel *model = [MyDataModel sharedDataModel];

See also this stack overflow discussion about singletons.


The most common way I've seen this is to set up the thing you want to access in the app delegate and reference it in other places like this:

MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate]; 
myStuff = appDelegate.stuff;

In the app delegate, set up a stuff variable and use @property and @synthesize as usual.

Some people say that it's not a good approach, since it's the same as using global variables, but it's very common.


I like to create a top level Model class that is a singleton and contains all the elements I might need.

It's helpful to also give it a top level load method that populates objects with just the db keys, using the hydrate/dehydrate pattern common in the Apple examples.

Typical usage in the app delegate would be simply,

[[MyModel sharedModel] load];

And then in a view controller:

NSArray *myThing1s = [[MyModel sharedModel] thing1s];
NSArray *myThing2s = [[MyModel sharedModel] thing2s];

You can then iterate over your thing1s and thing2s and when you need details, you can just call

[myThing1 hydrate];

which will populate the object.

Of course, you probably want to use CoreData to manage the persistence from 3.0 onwards.


I always create a special object called DataModel and use it's singleton sharedInstance.

And this object then holds all the app-related-data. No need for accessing the dreaded appDelegate.

DataModel.h

#import <Foundation/Foundation.h>

@class MyClass1, MyClass2;

@interface DataModel : NSObject

@property (copy, nonatomic) NSString *aString;
@property (assign) BOOL aBool;

@property (strong) MyClass1 *myObject1;
@property (strong) MyClass2 *myObject2;

+ (DataModel *)sharedModel;

@end

DataModel.m

#import "DataModel.h"
#import "Class1.h"
#import "Class2.h"

@implementation DataModel

- (id) init
{
    self = [super init];
    if (self)
    {
        _myObject1 = [[MyClass1 alloc] init];
        _myObject2 = [[MyClass2 alloc] init];
        aBool = NO;
        aString = nil;
    }
    return self;
}

+ (DataModel *)sharedModel
{
    static DataModel *_sharedModel = nil;
    static dispatch_once_t onceSecurePredicate;
    dispatch_once(&onceSecurePredicate,^
                  {
                      _sharedModel = [[self alloc] init];
                  });

    return _sharedModel;
}

@end

And (bacause I'm lazy) i put DataModel.h in application-prefix.pch.

That way i can access my data from anywhere in the application simply by calling

[DataModel sharedModel]