Search code examples
ioscore-datasingletonwebserver

iOS web API data management (singleton?)


This is a pretty typical scenario but I'd like to know what the best approach is.

Let's say I need to build an app that interacts with a REST API. The data from the web server is then displayed in multiple ways throughout the app.

Typically the way I handle this is to have a singleton handle all the data manipulation (both fetching/storing from/to the server and holding the data in memory. Then when I want to display this data in a tableview for example, I would access this singleton directly in the data source methods. For example [[MyApi sharedInstance] arrayOfCustomObjects];.

So basically whenever some part of the app needs to access data it does so by accessing the singleton.

Is this a good way to go about this? Are there any other patterns that might be more useful?

An alternative would be that instead of storing data in the singleton, have each controller hold instance variables to store the data they need and then use the singleton only to fetch from the server, but store the data themselves. The problem here is that if the controller gets dismissed prematurely then this instance variable disappears and the server access is wasted (but perhaps this is a good thing?).

Finally, what's a good strategy when you throw persistence into the mix? I imagine having CoreData sit between the network calls and the rest of the app would be a good approach?

I guess the real question here is what is the best approach for managing data that came from the server and should maybe be persisted?


Solution

  • The question is kind of broad, but I can tell you how I usually work.

    I typically have a singleton for the API client, implemented in this fashion

    + (instancetype)sharedAPI {
        static dispatch_once_t once;
        static id _sharedInstance;
        dispatch_once(&once, ^{
            _sharedInstance = [[self alloc] init];
        });
        return _sharedInstance;
    }
    

    Then I use RestKit to map my REST resources on CoreData entities automatically. The beauty of this approach is that I don't have to manually handle the CoreData persistency but I have RestKit caring about that for me at every API request.

    What my API client does is just to provide useful methods wrapping the RestKit APIs.

    For instance this is my API for retrieving the current user information

    - (void)getCurrentUserWithSuccess:(void (^)(HSUser *))success
                              failure:(void (^)(NSError *))failure {
        NSString * path = [NSString stringWithFormat:HS_API_USER_PATH, [HSUser currentUser].userId;
        [[RKObjectManager sharedManager] getObject:nil path:path parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
            HSUser * user = [mappingResult firstObject];
            if (success) {
                success(user);
            }
        } failure:^(RKObjectRequestOperation *operation, NSError *error) {
            NSLog(@"%@", error);
            if (failure) {
                failure(error);
            }
        }];
    }
    

    In my controllers' logic I can then call

    [[HSAPI sharedAPI] getCurrentUserWithSuccess:^(HSUser * user) {
        //do something
    } failure:^(NSError * error) {
        //do something else
    }];
    

    And as I was saying before, after such API call the HSUser instance corresponding to the current user is automatically persisted.

    I find it definitely convenient.