Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

More than one RKObjectManager at a time (RestKit)

I am testing out RestKit and need to access different BaseUrls and also sometimes access a web service with the same baseUrl from different places "at once", lastly I also need to access the same baseUrl with different ressourcePaths in the same controller.

In my app delegate I set up the RKObjectManager singleton like this.

RKObjectManager *objectManager = [RKObjectManager objectManagerWithBaseURL:kBaseUrl];
[objectManager registerClass:[EntityClass1 class] forElementNamed:@"element1"];
[objectManager registerClass:[EntityClass2 class] forElementNamed:@"element2"];
.
.
.
etc.

The singleton approach is really easy to work with, I however can't figure out how to separate the different web service calls.

In MyViewController, which implement the RKObjectLoaderDelegate, I will have the two methods:

- (void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects         {
    //stuff with result
}

- (void)objectLoader:(RKObjectLoader *)objectLoader didFailWithError:(NSError *)error {
    //stuff with error    
}

This causes no problems when MyViewController uses one RKObjectManager singleton to access one ressourcePath with one baseUrl.

If I start different requests in this way:

[[RKObjectManager sharedManager] loadObjectsAtResourcePath:FLICKRPath delegate:self]
[[RKObjectManager sharedManager] loadObjectsAtResourcePath:FOURSQUAREPath delegate:self]

and so on, within the same MyController, my problem is that FLICKRPath and FOURSQUAREPath of course has different baseUrl, but the RKObjectManager only has one?

If I get this working and can have different RKObjectManagers another problem arises. The delegate methods didLoadObjects and didFailWithError will receive results from both RKObjectManagers and I can't see any other way to tell them apart than from their baseUrls. Potentially comparing each return value with a baseUrl and, even worse, a ressourcePath, in the delegate method does not appeal to me at all.

If I have different RKObjectManagers I guess I could pass them different delegates and build classes dedicated to deal with the return values from different baseUrls and ressourcePaths. This would mean I had to build yet another abstraction on top of MyController and RestKit, which also seems messy.

I have a strong feeling I am going about this in the wrong way, the RestKit source is very impressive which indicates that is me fighting the framework. I would really appreciate some best practice insights on the subject. I have been through all the resources and examples that I could find but have not seen the above use case. It is always one RKObjectManager, one baseUrl and one ressourcePath.

Thank you in advance.

like image 722
RickiG Avatar asked Jun 01 '11 09:06

RickiG


1 Answers

Since there is no accepted answer yet: using multiple object managers is quite simple using RestKit.

From the Wiki (Using Multiple Base URLs (and Multiple Object Managers):

The first object manager you create will be the shared singleton RestKit uses by default. But by creating additional object managers, you can pull from their BaseURLs as needed, just be sure to retain these new managers.

RKObjectManager *flickrManager = 
    [RKObjectManager objectManagerWithBaseURL:flickrBaseUrl]; // <-- shared singleton
RKObjectManager *foursquareManager = 
    [[RKObjectManager objectManagerWithBaseURL:foursquareBaseUrl] retain]; // <-- you must retain every other instance.

Depending on your application, you may want to put this second object manager in a more accessible place, like a retained property on the AppDelegate, so that it's easy to pull from as needed. In the event that you need to differentiate between the results from your two (or more) object managers, simply set an identifier in the userData for the queries.

- (void)someAction(id)sender {
        // .......
        RKObjectLoader* loader = [[RKObjectManager sharedManager] loadObjectsAtResourcePath:@"/whatever" delegate:self];
        loader.userData = @"foursquare";
        // or do this, if you need a number instead of a string
        loader.userData = [NSNumber numberWithInt:1234];
        // .......
    }

//Then when the delegate comes back you can cast it into a string or number as appropriate:
- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects {
    // .......
    NSString* source = (NSString*) objectLoader.userData;
    // or, if you did the NSNumber instead:
    NSNumber* source = (NSNumber*) objectLoader.userData;
    // .......
}
like image 145
tilo Avatar answered Sep 22 '22 04:09

tilo