سؤال

I'm working on an app that uses CoreData alongside a server API. I'm simplifying a bit, but the tricky part is that when I update a relationship (add or remove an object from the relationship), besides saving this to CD, I also need to send separate HTTP requests to the server to add or delete such objects.

For instance (I'm obviously skipping the JSON <-> CD parsing aspect of this), say I:

  1. retrieve from the server object O with relationship R (to-many) initially holding another object r0. So that after a fetch to the server, my main context holds O.R = [r0].
  2. I then remove r0 and add r1. Now the main context holds O.R = [r1].

Currently, what I do when I want to commit this back to the backing SQL in the app and also the server is dispatching an async block on a private GCD queue. The block:

  1. Creates a temp context that only shares the store coordinator with the main context.
  2. retrieves the "saved" (in the SQL db) version of object O by ObjectID using the temp context.
  3. Does a diff by ObjectID between the elements in the version of O in the main context and the version just retrieved via the temp context. In this way I can tell that the version just retrieved via the temp context has O.R = [r0], while the current version from the main context has O.R = [r1].
  4. From the above, I know I have to issue one call to delete r0 from the server and another to add r1.
  5. Last, I save the main context, since as far as CoreData is concerned, O.R = [r1] is indeed the new state. (remember that figuring out what was deleted and what was added on a per-object basis is only necessary for the server update).

Now the problem is, that I want to do this using child contexts and -perfromBlock: instead. But if I create a child context of the main context instead of a temp context that only shares the store coordinator with the main context, I can't seem to find a way to access the "old" version of the object in question from the SQL. That is, after the change, the main context has O.R = [r1]. And if I fetch the same object via the child context by id, I also get that O.R = [r1]. Also, I tried calling -refreshObject: on the child context to see if this would force the child to refetch from the SQL, but it still reflects the current state of the main context. I think this has to do with a cache that I don't know how to clear.

Point being, is there a way to force the child context to fetch from the persistent store instead of the cache? Or is there another way to fetch the "old" state of the object in question?

BTW, neither -changedValues nor -changedValuesForCurrentEvents seem to do the trick either.

هل كانت مفيدة؟

المحلول

There is no way to force the child to get the saved state instead of the current state.

You either need to fetch the objects before modifying them or you need to have a separate sibling. Another option would be to have a completely separate stack including the PSC.

Update

Siblings are two contexts that extend from the same NSPersistentStoreCoordinator or from the same parent context.

Fetching beforehand. Create the child context, fetch the objects that are going to be modified in the child. Then modify the objects in parent. The children will not be modified because context changes do not get pushed down.

this is a hack. Core Data is not designed to work like this. CD is an object graph first and it works very hard to keep everything in sync. I would re-think what you are doing and find a cleaner solution.

Update

There is no documentation on how iCloud works internally. However, if I were to write it I would listen for the NSManagedObjectContextDidSave notification and then based on the insert, update and delete sets I would build the transaction log.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top