0

The issue:

I'm reading Tim Roadley's "Learning Core Data of iOS". I don't understand why the author takes an extra, seemingly superfluous step when retrieving a managed object from a fetched results controller.

NSManagedObjectID *itemId = [[self.fetchedResultsController objectAtIndex:indexPath] objectID];

// Item is a NSManagedObject subclass
Item *item = (Item *)[self.fetchedResultsController.managedObjectContext existingObjectWithID:itemId error:nil];

// gets and sets item's attributes…

Isn't that weird? Why go to the trouble of using the objectID and the existingObjectWithID:error: method rather than just use the fetched results controller's objectAtIndexPath: method to retrieve the item object?

What I have done to try and understand:

(1.) I searched the entire electronic version of the book for the existingObjectWithID:error: method. The method is used throughout the book, but I couldn't find an explanation for its usage.

(2.) I read the Apple docs on existingObjectWithID:error:

If there is a managed object with the given ID already registered in the context, that object is returned directly; otherwise the corresponding object is faulted into the context. This method might perform I/O if the data is uncached. Unlike objectWithID:, this method never returns a fault.

The object may be "faulted into the context", but the method "never returns a fault". Isn't that contradictory? Suffice it to say that the docs aren't helping me wrap my head around this.

(3.) I thought about it for a day, still no epiphany. However, I suspect the answer has something to do with saving in the background, which will be added to the book's demo app later.

bilobatum
  • 8,918
  • 6
  • 36
  • 50

2 Answers2

2

The step is unnecessary. While Joseph explains a justification for it, it doesn't really apply. When an object is deleted the NSFetchedResultsController will detect the deletion and react appropriately.

I suspect that Joseph is correct that the author is trying to avoid deleted objects but that is not the right way. If you NSFetchedResultsController is returning deleted objects or an object is being deleted from underneath the NSFetchedResultsController then you application has other, probably threading related, issues.

Just use -objectAtIndexPath:.

Update

If you were fetching managed objects without a NSFetchedResultsController, would JosephH's justification hold?

The solution he is discussing is a bandaid that covers a real problem.

If an application is running into a situation where objects are being deleted from under it then there is a bigger issue that needs to be solved.

Will it work? yes.

Is it the right answer, no.

Marcus S. Zarra
  • 46,571
  • 9
  • 101
  • 182
  • If you were fetching managed objects without a NSFetchedResultsController, would JosephH's justification hold? – bilobatum Feb 12 '14 at 03:19
  • That's definitely a good point; it really *shouldn't* be necessary in this case. I don't know why the original author wrote that code like that. – JosephH Feb 12 '14 at 11:07
  • What kind of threading issue could cause this? I'm seeing entities in my 'fetchedObjects` array that have `deleted == true`. – AnthonyMDev Aug 30 '16 at 21:42
  • @AnthonyM A number of things can cause the issue, probably best to open your own question and lay out what you are doing and what you are seeing. – Marcus S. Zarra Aug 31 '16 at 02:51
1

The discussion on How can I tell whether an `NSManagedObject` has been deleted? is likely to be helpful.

Essentially, the check is there to make sure the object really still exists before using it. If you don't do that, you might get an exception (or other bad behaviour) when you try to use the object if another view controller has deleted it from the context and saved that context.

The existingObjectWithId will return nil if the object has been deleted & that delete has been saved.

Community
  • 1
  • 1
JosephH
  • 37,173
  • 19
  • 130
  • 154