Does Content of Child Managed Object Context Always the Same with Content of it's Parent?
Asked Answered
B

2

17

How to update child managed object context so it has the same data with parent?

As far as I know, when saving, child only goes one step, namely to parents. Yet when fetching fetch always go really deep all the way to the parent and persistent store. So I expect things will be the same.

Yet it's not.

I have a managed object context that is parent of all other managed object context.

One child change data and save. The parent is also changed. I do executeFetchRequest on parent and I see that the data change.

However, some child of the parents still use old data. Same object id same data. Somehow the value of the property remain the same.

How to tell the child to reload fresh data from the parent?

To be more exact

Say P is the parent

Say it has C1 C2 C3 as child

Then C1 changes data and commit. The change is propagated to P. However, executing executeFetchRequest at C2 and C3 still shows old data.

What gives?

For example, when I check for the imageBlob property, this is what I get:

Child:

2013-02-05 13:57:42.865 BadgerNew[78801:c07] imageBlob: <UIImage: 0x89c3c50>
2013-02-05 13:57:42.866 BadgerNew[78801:c07] imageBlob: <null>
2013-02-05 13:57:42.866 BadgerNew[78801:c07] imageBlob: <null>
2013-02-05 13:57:42.866 BadgerNew[78801:c07] imageBlob: <null>

Parent:

2013-02-05 13:57:42.868 BadgerNew[78801:c07] imageBlob: <UIImage: 0x114af650>
2013-02-05 13:57:42.868 BadgerNew[78801:c07] imageBlob: <UIImage: 0x8e492e0>
2013-02-05 13:57:42.868 BadgerNew[78801:c07] imageBlob: <UIImage: 0x114c79b0>
2013-02-05 13:57:42.869 BadgerNew[78801:c07] imageBlob: <UIImage: 0xa8c76e0>

Here is a more comprehensive version why I jot down the moc, the parent moc, the blob, the URL and the object ID. Child:

In particular I want the mainqueue managedobject context to be another child of the parent rather than the parent of all other managedObjectContext. On the other hand, I also want the mainQueue Managed object context to have uptodate information. I wonder what the standard solution be.

Beckner answered 4/2, 2013 at 13:29 Comment(1)
Wow I put 50 bounties and got 5 votes so, I got 10 points back :)Beckner
S
21

The child has invalid existing references. If you want the siblings to be in sync after parent save, you must invalidate the children with reset.

After calling reset, all the receiver's managed objects are “forgotten.” If you use this method, you should ensure that you also discard references to any managed objects fetched using the receiver, since they will be invalid afterwards.

You can also use refreshObject:mergeChanges: on the individual objects changed on all the child contexts when saving the parent context if you want finer control on changed objects in the child contexts.

Serial answered 8/2, 2013 at 6:20 Comment(4)
While it's true using reset is kind of overkill. I am finding other solution.Beckner
I added the method to update individual managedobjects in the context.Serial
Bravo :) I used that actually. Enjoy the bounty :) And ugh, anyone knows why the question is downvoted?Beckner
I did chose this as the right answer right? Want to make sure you got the bounty.Beckner
L
0

There is actually a lot of documentation about how to do this correctly, including WWDC session videos from 2011 and 2012. 2012 session 214 "Core Data Best Practices" would be especially interesting for you.

For example, for your save, it should look like:

 [child performBlock:^{
     [child save:&error];
     [parent performBlock:^{
         [parent save:&parentError];
     }];
 }];

That saves the child, the changes go to the parent and you save on the parent - which would propagate all of those changes correctly to other child contexts. Looking at your question, I think you may run into some other issues with your implementation and Session 214 may be very helpful in resolving them.

As for resetting the context, I would NOT recommend doing that when using parent child contexts. I would also steer away from using refreshObject:mergeChanges: . Using objectWithID for this purpose may save you a lot of pain as it will make the best use of the managed object context's row cache. It will also only traverse as far as it needs to through the stack of children and parents to satisfy the request.

Leolaleoline answered 12/2, 2013 at 20:8 Comment(14)
That is EXACTLY the problem. I thought, change the parent, change all the child. NO. As Fruity Geek said, the core data practice for reloading data from parent is shaky. What core data do, is to use existing data on the child if it exist. Only if it doesn't exist or stale core data would look deeper.Beckner
+1 for showing that I should called [parent performBlock] within [child performBlock]Beckner
But Fruity Geek answer is more correct. I'll choose him unless there is any more better answer, which I can't think of.Beckner
I would highly recommend watching session 214 before you proceed with your implementation. It's even on iTunes. developer.apple.com/videos/wwdc/2012Leolaleoline
Changes from parent context are not propagated to children contexts when parent context is saved. Here is a citation from Core Data 2nd edition by Marcus Zarra: "It should be noted that while the changes will get pushed up to the parent context, they will not get pushed down to any existing children. It is best to treat existing children as "snapshots" of the data taken at the time that the child was created."Ginaginder
That is misleading. If you were to look at slide 44 of the WWDC presentation cited above, you might read "Parent context acts like a persistent store for the child. Children see state as it is in the parent. Children inherit unsaved changes from the parent. Children marshal their saves in memory to the parent". The parent does not have to be saved for children to see changes. For a save in a child to be reflected in the parent however, you must push it up yourself using the method above.Leolaleoline
@Leolaleoline I'm sorry, but you are wrong. Children do inherit the unsaved changes from the parent, but any changes made to the parent after the child context has been created remain invisible to the child, if the child already has that object filled from fault. If the object is faulted, it will be fetched from the parent context and will be visible.Bye
@svena, please re-read my comment. In the scenario you describe what SHOULD be happening if that if the child does not have a snapshot it goes to the parent to fulfill it, and if necessary it walks all of the contexts to the store to fulfill it. If the parent has the object and it has been changed since the child was created, it will be fulfilled from the parent correctly if you use objectWithID: , which is the preferred method. You can see this in action in the debugger easily.Leolaleoline
@Leolaleoline Yes, it will be fulfilled from the parent if a fault is fired and all the way down to the persistent store, if necessary, just as you say it. BUT... if the object already lives in the child context and changes are made to the parent, those changes need to be explicitly merged to make them available in the child context.Bye
So, even if I use objectWithID, if the child think that the object is not at fault then the child would just use it's version.Beckner
objectWithID will only pull as many levels as it needs to. This is covered in several WWDC sessions.Leolaleoline
I accidentally stumbled upon this rather old answer, but after reading it again, I decided to down vote it because it is untrue, which I have previously pointed out in my comments as well.Bye
@Bye i dont understand what is wrong with the answer. All i can see is that quellish's comment might be misleading in light of your clarification.Carruth
@SaadMasood Both the answer and later comments are misleading to solve the problem raised by the question, that is how to refresh data in the child context from its parent context. The first part of the answer, referencing Core Data best practices on how to merge changes in the child context into the parent context however are correct.Bye

© 2022 - 2024 — McMap. All rights reserved.