2

My app has two views managed by a Tab Bar Controller. One of the views is Google Map (GMSMapView using their SDK) and the other is a TableView showing a list of the same data. The markers on the map are the same data in the TableView (just alternate presentations of the same data).

I fetch the data from an NSURLSessionDataTask. I'm wondering what is the best way to share that data between the two views. Obviously, I don't want to fetch the data twice for each view. But I'm not sure what is the best practice for making that shared data available/synched between the two views.

A similar question was asked but not answered here.

Community
  • 1
  • 1
emersonthis
  • 32,822
  • 59
  • 210
  • 375
  • A minor quibble, but Tab Bar Controllers manage ViewControllers, not views. So perhaps you mean you have one ViewController with the GMSMapView as a subview, or set as the ViewControllers view? Same with UITableView. – Acey Aug 09 '14 at 17:56
  • @Acey That's correct. That's what I mean. – emersonthis Aug 09 '14 at 19:11

4 Answers4

2

You can create a model class which holds the map related data in an array/dictionary/custom class objects. You can make this model class as a singleton(can be initialized only once). Both view controllers (i.e the map and table view) can refer to this model to populate date in different views now.

Model Class
-----------

@property (strong, nonatomic) MyCustomDataRepresentationObj  *data;

+ (id)sharedModel {
    static MyModelClass *sharedModel = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedModel = [[self alloc] init];
    });
    return sharedModel;
}

-(void)fetchMapDataWithCompletionBlock:(void(^)(id response, NSError *error)onComplete
{
    // Check if data is available.
    // Note: You can add a refresh data method which will fetch data from remote servers again.
    if (!data) {
    __weak MyModelClass *weakSelf = self;
    // Make HTTP calls here, assume obj is returned value.
    // Convert network response to your data structure
    MyCustomDataRepresentationObj *objData = [MyCustomDataRepresentationObj alloc] initWith:obj];
    // Now hold on to that obj in a property
    weakSelf.data = objData;
    // Return back the data
    onComplete(objData, error);
    } else {
    onComplete(objData, nil); // Return pre fetched data;
    }
}

Now in view controllers you would have to call the model class method which will inturn make the network call(if needed) and returns data in completion block.

View Controller 1
-----------------

-(void)viewDidLoad
{
    // This is where the trick is, it returns the same object everytime.
    // Hence your data is temporarily saved while your app is running.
    // Another trick is that this can be accessed from other places too !
    // Like in next view controller.
    MyModel *myModelObj = [MyModel sharedModel];
    // You can call where ever data is needed.
    [myModelObj fetchMapDataWithCompletionBlock:^(id response, NSError *error){
        if (!error) {
            // No Error ! do whats needed to populate view
        }
    }];
}

Do the same in other view controller.

View Controller 2
-----------------

-(void)viewDidLoad
{
    // Gets the same instance which was used by previous view controller.
    // Hence gets the same data.
    MyModel *myModelObj = [MyModel sharedModel];
    // Call where ever data is needed.
    [myModelObj fetchMapDataWithCompletionBlock:^(id response, NSError *error){
        if (!error) {
            // No Error ! do whats needed to populate view
        }
    }];
}

Note: I have just jotted down these lines of code here, there might be syntax errors. Its just to get the basic idea.

GoodSp33d
  • 6,252
  • 4
  • 35
  • 67
1

A UITabBarController act as a Container. So from your 2 child ViewControllers, you can access the TabBarViewController with the property parentViewController.

So if you want to share the same data with your 2 child ViewControllers, you can fetch and store your data in your UITabBarController. And, from your UIViewControllers, you can access it like this

MyCustomTabBarController *tabBar = (MyCustomTabBarController*)self.parentViewController;
id data = tabBar.myCustomData;
matt.P
  • 136
  • 3
0

Use Singleton Patterns create a singleton class and initialize singleton instance in your AppDelegate.m this way you can access your singleton class instance from your AppDelegate by using

Husrat Mehmood
  • 2,270
  • 1
  • 20
  • 22
0

How about a data fetching object? Make a new class that makes requests for your data bits and stores the results internally.

You then could get the data into your ViewController with a number of different methods:

Direct Reference Associate this object with each ViewController as a property on the ViewControllers before setting the viewControllers property on the Tab Bar Controller.

Your interface to this new class could include the set of fetched results, as well as a method (with a callback when the request finished perhaps) to tell the object to fetch more results.

Notification Center Your object could post notifications when it has more data, and just include a method to start requesting more data.

Delegate + Registration You could create a protocol for objects that want to get told about changes to the data set, make sure all of your necessary ViewControllers conform, and have a delegates NSArray property on your data fetching object. This is far more manual than Notification Center, but it's slightly easier if you need a very robust interface.

Needless to say, there are a lot of ways to handle this, but they all start with designating a class to do the specific task of fetching/storing your data.

Acey
  • 8,048
  • 4
  • 30
  • 46