Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best practice for temporary objects in RestKit with Core Data

Background: I have a managed object, Car. I have a RESTful search API sitting on localhost/cars/search. The returned results are Car objects from the server side, but I only want to save the one the user chooses. The rest of the Cars I want to discard when they tap back out of Search.

At first I was all like:

@interface Car : NSManagedObject  //<--- managed object

    @property (nonatomic, strong) NSNumber* year;
    @property (nonatomic, strong) NSString* make;
    @property (nonatomic, strong) NSString* model;

@end

@interface TransientCar : NSObject //<--- regular NSObject!

    @property (nonatomic, strong) NSNumber* year;
    @property (nonatomic, strong) NSString* make;
    @property (nonatomic, strong) NSString* model;

@end

I was mapping the REST API search results JSON into TransientCar objects for the purposes of displaying search results, but not saving them to the context. By default, if you map a managed object, RestKit will call its +object convenience factory to create the object and insert it into the current context (hard-coded to sharedManager's object store's context, btw!)

This seemed unsustainable. So now I'm just using NSMutableDictionary to hold the search result data until the user taps into a detail view and does something worth saving a real managed object for:

RKObjectMapping* tempCarMapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]];
[tempCarMapping mapKeyPathsToAttributes:
 @"year", @"year",
 @"make", @"make",
 @"model", @"model",
 nil];

Is this a good practice? Using NSMutableDictionary as a temporary representation until the user does something that warrants inserting a new object into the context? I was kind of a fan of using the original managed object subclass to represent the data, but somehow being able to flag it as "don't keep" or something, but every time I do that I feel like I'm fighting the framework (and race conditions). I also tried using a scratch/throwaway context by creating a new RKObjectManager and just clearing its whole context afterwards, but RestKit's ActiveRecord category's +managedObjectContext method is hardcoded to return:

[[[RKObjectManager sharedManager] objectStore] managedObjectContext];

That sort of scuttles the possibility of ever using a scratch context for temp/trash data.

like image 359
Eric G Avatar asked Mar 27 '12 19:03

Eric G


3 Answers

Unfortunately, I don't as yet have enough StackOverflow reputation to put this answer where it belongs (as comments to the other replies), but I wanted to add some points.

I believe that Evan Cordell's answer is flawed. The current restkit version (0.10.x) doesn't let you create contexts for the RKManagedObjectLoaders to use, and the RKObjectManagers can take a store, but it has to be of type RKManagedObjectStore, which is explicitly tied to sqllite. The dev version of restkit (0.20) apparently relaxes that, so you can have it save the data to an in-memory database. I did try overriding the RKManagedObjectStore methods to use a context I provided, but it didn't work ... at any rate, the fix appears to be non-trivial.

The other link given, Better Approach for Creating Temp Object for Core Data with Restkit, appears to do with posting an object and receiving the same object in the response. It's a different problem than was posed in this question.

Until v.0.20.x is released, which will hopefully be soon, it appears that a parallel class hierarchy is the only choice. If I'm incorrect, I welcome correction on this point!

like image 98
J.Z. Avatar answered Nov 23 '22 04:11

J.Z.


First, I've done this in the past using your method of having two copies of the model, one which is for Core Data and one which is transient (just an NSObject). That worked without any problems for me.

As for your other attempts, I don't think the library forces your hand as much as you think. Look at the API for RKManagedObjectStore and NSManagedObject+ActiveRecord. In particular, RKManagedObjectStore has a managedObjectContext property, a method - (NSManagedObjectContext*)newManagedObjectContext and several methods for merging changes.

You're right that [NSManagedObject managedObjectContext] always returns the sharedManager's context - but that makes sense, it's a class method. Otherwise how would the class know which context to return? But it's moot since there are so many other ways to create new contexts and access them. Or sidestepping that entirely, you could just keep a reference to your temporary context and use it directly.

This gives you a few options: have multiple ObjectManagers, have one object manager but create a temporary context from it and only keep the objects you want, create a transient object based on the managed object.

The NSMutableDictionary option doesn't seem as flexible as the other methods, but I wouldn't say it's "bad practice."

like image 28
Evan Cordell Avatar answered Nov 23 '22 04:11

Evan Cordell


You can also see this answer: Better Approach for Creating Temp Object for Core Data with Restkit

It will avoid the transient object problem mentioned in the answer by Evan Cordell, who is a major contributor to RestKit.

like image 45
Paul de Lange Avatar answered Nov 23 '22 05:11

Paul de Lange