78

CoreData Entity "A" has a one-to-many relationship to a collection of CoreData Entries "B", using a Cascade delete rule.

In an iCloud environment, while device 1 shows a detail view of one of the "B" entries, device 2 deletes the "A" entry.

When the NSPersistentStoreDidImportUbiquitousContentChangesNotification notification is received in device 1, its App Delegate calls mergeChangesFromContextDidSaveNotification and then broadcasts an internal notification which is captured by the view controller showing the details of entry "B" (the code uses performBlock where it should).

However, although entry "A" is indeed nullified when the detail view controller receives the internal notification, entry "B" still exists as a valid CoreData object. It seems that the Cascade rule hasn't completed its operation yet. Therefore the view controller in device 1 isn't aware of the delete, which may lead to unexpected results.

mergeChangesFromContextDidSaveNotification appears to return prematurely, when the base data has been merged but the Cascade rule hasn't completed yet.

I tried to refresh entry "B" when the notification arrives while temporarily setting the stalenessInterval of the managed object context to zero so a cached object won't be used, but I still get a valid entry "B" from the store.

Checking for a null entry "A" at this point is not an option, because the situation is somewhat more complex than what I described here and a null entry "A" can be valid in some cases.

I tried to introduce a delay after merging the changes and before sending the internal notification to the view controllers. I found out that a 2-second delay doesn't help, but a 10-second delay works.

But I don't want to rely on this delay. This is a test environment without much data, and I don't know what will happen in a production environment. Relying on an experimental delay doesn't seem the right thing to do.

Is there a right thing? Or am I doing something wrong to begin with?

Charles
  • 50,943
  • 13
  • 104
  • 142
Amiram Stark
  • 2,208
  • 22
  • 32
  • There's more to it than seems since the cascade deletes are propagated as soon as which comes first: processPendingChanges, save or end of a run loop cycle. In normal conditions the issue you describe should not exist. – svena May 26 '12 at 17:11
  • is the managed object ID for the object in the detail view controller in the NSDeletedObjectsKey array that comes with the NSPersistentStoreDidImportUbiquitousContentChangesNotification? – ImHuntingWabbits Jun 13 '12 at 16:19
  • Is this always happening or is it intermittent ? I have a complex hierarchical structure and haven't seen any orphans yet! Are you fetching entity B again, or could it be that because you are displaying it somehow you are retaining a reference to the object. What happens if you close the app and reopen it, it entity B still there ? – Duncan Groenewald Oct 11 '13 at 20:35
  • 3
    @Amiram One and half years. Did you get your answer? :) – Ravindra S Dec 17 '13 at 19:02

1 Answers1

1

From experience, listening to notifications other than NSManagedObjectContextDidSaveNotification is a big mess and can lead to relying on properties not yet updated. The detail view controller should listen to NSManagedObjectContextDidSaveNotification notifications, which are thrown after cascade is applied. You can then check by several means if the current object is valid or not (you can check to see if the current object's managed object context is nil or you can perform a fetch and see if the object exists in the store).

Léo Natan
  • 56,823
  • 9
  • 150
  • 195