How do I share an object between UIViewControllers

2019-01-06 09:49发布

My application is a tab bar application, with a separate view controller for each tab.

I have an object in my first view controller (A) which contains all my stored application data (Please ignore NSUserDefaults for this) which needs to be accessed by the second view controller (B) when I press a button on it. How can I achieve this in the best way?

5条回答
三岁会撩人
2楼-- · 2019-01-06 10:14

Both view controllers should reference a third object (C) as their dataSource; this object (C) containing all the stored application data.

C would be, in this case, the M in the MVC.

Add to each of your ViewControllers the following declarations:

// SomeViewController.h
// Before @interface

@class MyDataSource;

// In the interface

IBOutlet MyDataSource *datasource;
@property(retain) IBOutlet MyDataSource *datasource;
查看更多
相关推荐>>
3楼-- · 2019-01-06 10:18

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.

查看更多
男人必须洒脱
4楼-- · 2019-01-06 10:28

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.

查看更多
在下西门庆
5楼-- · 2019-01-06 10:29

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.

查看更多
来,给爷笑一个
6楼-- · 2019-01-06 10:29

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]
查看更多
登录 后发表回答