Alex Kurkin
Alex Kurkin

Reputation: 1069

How to discard CoreData changes in one object when RKObjectManager failed to post object

how to discard CoreData changes made to an instance of NSManagedObject when POST/PUT request of this object fails in RKObjectManager?

NSManagedObject *object = ...;
[object setValue:@"test" forKey: @"test"];
[[RKObjectManager sharedManager] postObject:object 
                                 parameters:nil 
                                    success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) { NSLog(@"success, nothing to do"); }
                                    failure:^(RKObjectRequestOperation *operation, NSError *error) { 
  // I want to discard changes made to object here 
}

UPDATE: RestKit 0.20

Upvotes: 15

Views: 4953

Answers (3)

Marc Etcheverry
Marc Etcheverry

Reputation: 1089

An alternative solution is to refresh the values yourself.

The refresh method from the NSManagedObjectContext can cause issues if you have more than one reference to an object, and especially if another class is doing KVO on properties. Upon refresh you will get objects that are faulted (all properties are nil) but that are in a broken state, receiving the error message _cd_rawData but the object is not being turned into a fault when you try to access any properties.

Here is the alternative if you don't want to use a separate context and NSUndoManager:

extension NSManagedObject {
    func revertToCommitedValues() {
        changedValues().keys.forEach { (key) in
            if let persistentValue = committedValues(forKeys: [key])[key] {
                if persistentValue is NSNull {
                    setValue(nil, forKey: key)
                }
                else {
                    setValue(persistentValue, forKey: key)
                }
            }
        }
    }
}

Note that NSManagedObject's changedValues method does not reflect changes inside of relationships, so if you want a 'deep reset' you will have to call that method on each of your relationships

You can build on this method to only refresh certain properties, of course.

Upvotes: 0

Vasilii Muravev
Vasilii Muravev

Reputation: 3163

Swift solution:

import CoreData

extension NSManagedObject {
    func cancelChanges() {
        managedObjectContext?.refresh(self, mergeChanges: false)
    }
}

Using:

object.cancelChanges()

Upvotes: 4

Dan Shelly
Dan Shelly

Reputation: 6011

I know nothing about RKObjectManager, but in order to discard changes to NSManagedObject instance you could call:

[object.managedObjectContext refreshObject:object mergeChanges:NO]

This will discard all changes and turn the object into fault.

see here

Upvotes: 46

Related Questions