8
votes

I'm curious to know what the best way is to create a new NSManagedObject in RestKit 0.20? Currently my code looks something like this:

#pragma mark - navigation buttons

- (void)createButtonDidTouch
{
    // create new album object    
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    NSManagedObjectContext *parentContext = RKObjectManager.sharedManager.managedObjectStore.mainQueueManagedObjectContext;
    context.parentContext = parentContext;
    NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Album" inManagedObjectContext:parentContext];
    Album *newAlbum = [[Album alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:context];

    // pass object to create view to manipulate
    AlbumCreateViewController *createViewController = [[AlbumCreateViewController alloc] initWithData:newAlbum];
    createViewController.delegate = self;
    createViewController.managedObjectContext = context;

    UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:createViewController];
    navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;

    [self presentViewController:navController animated:YES completion:nil];
}

#pragma mark - create view controller delegate

- (void)createViewControllerDidSave:(NSManagedObject *)data
{
    // dismiss the create view controller and POST

    // FIXME: add restkit code to save the object
    NSLog(@"save the object...");

    NSDictionary *userInfo = [KeychainUtility load:@"userInfo"];
    NSString *path = [NSString stringWithFormat:@"/albums/add/%@/%@", userInfo[@"userID"], userInfo[@"apiKey"]];

    [RKObjectManager.sharedManager postObject:data path:path parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
        operation.targetObject = data;
    } failure:^(RKObjectRequestOperation *operation, NSError *error) {
        NSLog(@"create album error: %@", error);
    }];

    [self dismissViewControllerAnimated:YES completion:nil];
}

- (void)createViewControllerDidCancel:(NSManagedObject *)data
{
    // dismiss the create view controller

    NSLog(@"delete the object...");
    // FIXME: add restkit code to delete the object

    [self dismissViewControllerAnimated:YES completion:nil];
}

I'm also curious to know what my responsibilities are for saving / deleting this object. If I POST to the server via RestKit is the managed object context saved?

What if I decide to cancel this creation process — what's the preferred way to delete this object?

Basically how much is RestKit doing for me, and what should I make sure I'm doing. I haven't found much documentation on this and would like to be clear on it.

2

2 Answers

11
votes

When you initialize an RKManagedObjectRequestOperation for a given object, RestKit will obtain a permanent object ID for that object and then create a child managed object context whose parent context is the context the object is inserted into. The operation then executes the HTTP request to completion and obtains a response.

If the response is successful and the mapping of the response is successful (note that the mapping occurs within this private child context), then the private child context is saved. The type of save invoked is determined by the value of the savesToPersistentStore property (see http://restkit.org/api/0.20.0/Classes/RKManagedObjectRequestOperation.html#//api/name/savesToPersistentStore).

When YES, the context is saved recursively all the way back to the persistent store via the NSManagedObjectContext category method saveToPersistentStore (see http://restkit.org/api/0.20.0/Categories/NSManagedObjectContext+RKAdditions.html).

When NO, the context is saved via a vanilla [NSManagedObjectContext save:] message, which 'pushes' the changes back to the parent context. They will remain local to that context until you save them back. Keep in mind that managed object context parent/child hierarchies can be as long as you create within the application.

If the HTTP request failed or there was an error during the mapping process, the private context is not saved and the operation is considered failed. This means that no changes are saved back to the original MOC, leaving your object graph just as it was before the operation was started (except the object being sent, if temporary, now has a permanent object ID but is still unsaved).

3
votes

The way you do it should works (calling each time the MOC in each of your VC), but is not "recommended".

What Apple suggests, just like any Core Data app, is the "pass the baton" style.

Nested contexts make it more important than ever that you adopt the “pass the baton” approach of accessing a context (by passing a context from one view controller to the next) rather than retrieving it directly from the application delegate.

See here: http://developer.apple.com/library/ios/#releasenotes/DataManagement/RN-CoreData/_index.html

As for your second question, RestKit should manage saving/updating your Core Data stack upon success of your api calls if everything is well mapped/setup.

From blake the RK creator:

if you POST or PUT a Core Data object, RK obtains a permanent object ID for it and then creates a secondary managed object context, fires the request, and maps the response (if possible). if the response and the mapping are successful, it will either save it back to the parent context or all the way back to the persistent store (i.e. into SQLite) based on the value of the savesToPersistentStore.