R – Dealing with variable assignments and async requests

asynchronouscocoacocoa-touchiphone

I'm looking for a reliable design for handling assignments that have asynchronous requests involved. To further clarify, I have a class which handles Data Management. It is a singleton and contains a lot of top level data for me which is used throughout my iPhone application.

A view controller might do something such as the following:

users = [MySingleton sharedInstance].users;

MySingleton will then override the synthesized users getter and see if it is set. If it is not set, it will speak to a Connection Manager (a wrapper for NSURLConnection and its delegate methods) which fires off an asynchronous request, and this is where problems begin. I cannot guarantee when "users" will be available. I could change the request to synchronous, but that will directly effect user experience, especially in a mobile environment where bandwidth is limited already.

I need to be able to at some point, have some kind of locking/synchronization code going on in my getter that doesn't return users until it is available or is nil.

Once the NSURLConnection has the data available, it needs to callback something/somewhere with a response object and let the getter know the data is available.. whether it's failed or succeeded.

Any suggestions on handling this?

Best Answer

I solved this problem a couple ways in different apps.

One solution is to pass an object and selector along to notify such as:

- (id)getUsersAndNotifyObject:(id)object selector:(SEL)selector

This breaks the nice property behavior however. If you want to keep the methods as properties, have them return immediately, with either cached data or nil. If you need to go out to the network, do so asynchronous and then let the rest of the app know the data changed via KVO or the NSNotificationCenter. (Cocoa Bindings would be an option on the Mac, but they don't exist on iPhone).

The two methods are fairly similar. Register for updates with your shared instance, and then ask for the data. KVO is a little lighter weight if you just dealing with raw observable properties, but an NSNotification might be more convenient if you're interested in several different pieces of data.

With an NSNotification, the client object could register for one type of notification which includes the changed data in its userInfo dictionary instead of having to register obvservers for every single key path you're interested in.

An NSNotification would also allow you to pass back failures or other status information a lot more easily than straight KVO.

KVO method:

// register observer first so you don't miss an update
[[MySingleton sharedInstance] addObserver:self
                               forKeyPath:@"users"
                                  options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld)
                                  context:&kvo_users_context];
 users = [MySingleton sharedInstance].users;

 // implement appropriate observeValueForKeyPath:ofObject:change:context: method

NSNotification Method:

 [[NSNotificationCenter defaultCenter] addObserver:self
                                          selector:@selector(sharedDataChanged:)
                                              name:MySingletonDataUpdatedNotification
                                            object:[MySingletonDataUpdatedNotification sharedInstance]];
 users = [MySingleton sharedInstance].users;

 // implement appropriate sharedDataChanged: method
Related Topic