Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CoreData could not fulfill a fault for when objects are updated by HTTP service

I think I understand the error message: CoreData could not fulfill a fault, but I am not sure how I should deal with it.

We have an application where we use Core Data to persist data returned from a JSON service. Today I am doing the following.

  1. Fetch local object from persistent store and return to UI
  2. Ask server if the object is updated - when I get the answer, I update the Core Data managed object
  3. Update UI with the updated object

The problem is; even if I do not use multi threads I sometimes gets an error when the HTTP request deletes managed objects that my UI has retained. I tried to fetch the objects with returnsObjectsAsFaults to NO. I thought I then could access all the relations and properties of an managed object even if it was deleted (as long as my UI had retained it).

How should I solve this issue?

I thought I could use separate NSManagedObjectContext for read and write. I have made this test:

MyAuthorMO *authorUpdate = [[MyAuthorMO alloc] init]; // I have made this init insert the object into the updateContext
authorUpdate.firstname = @"Hans";
authorUpdate.lastname = @"Wittenberg";
authorUpdate.email = @"[email protected]";

NSManagedObjectContext *updateContext = [[MyCoreManager getInstance] managedObjectContext];

NSError *error = nil;
[updateContext save:&error];

NSManagedObjectContext *readContext = [[MyCoreManager getInstance] readOnlyContext];

NSFetchRequest *fetchRequest = [managedObjectModel fetchRequestFromTemplateWithName:@"authorByEmail" substitutionVariables:[NSDictionary dictionaryWithObject:@"[email protected]" forKey:@"EMAIL"]];
[fetchRequest setReturnsObjectsAsFaults:NO];

NSArray *authors = [readContext executeFetchRequest:fetchRequest error:&error];

MyAuthorMO * readAuthor = [authors objectAtIndex:0];

// Delete the author with update context:
[updateContext deleteObject:authorUpdate];
[updateContext save:&error];

NSLog(@"Author: %@ %@, (%@)", readAuthor.firstname, readAuthor.lastname, readAuthor.email);

The log is outputted just fine as long as I use the readContext for the fetch. If I use the updateContext for the fetch, I get an exception. This looks promising, but I am afraid that I will run into problems at a later stage. Sooner or later I will probably try to access a property that is not fetched completely (a fault). How can I achieve the behaviour I am looking for?

like image 859
Andreas Aarsland Avatar asked Sep 09 '10 22:09

Andreas Aarsland


1 Answers

You shouldn't retain managed objects that the context has released. Let the context do that for you.

The problem is that managed objects can exist as either faults or actualized objects. When you retain one, you may retain the fault which contains no data. Even if you do retain the actual object, the object may not behave properly once it has been separated from its context.

In order to handle your scenario, you need a context for the UI and then a context for the server. After either context makes changes, you should merge the context to ensure both are properly updated relative to the store.

Your UI should be configured to reflect the state of data model, you shouldn't have parts of the data model dependent on the state of the UI.

like image 102
TechZen Avatar answered Sep 17 '22 04:09

TechZen