Correct implementation of parent/child NSManagedObjectContext
The parent/child MOC model is a really powerful feature of Core Data. It simplifies incredibly the age-old concurrency problem we used to have to deal with. However, as you've stated, concurrency is not your issue. To answer your questions:
- Traditionally, you use the
NSMainQueueConcurrencyType
for theNSManagedObjectContext
associated with the main thread, andNSPrivateQueueConcurrencyType
s for child contexts. The child context does not need to match its parent. TheNSConfinementConcurrencyType
is what allNSManagedObjectContext
s get defaulted to if you don't specify a type. It's basically the "I will managed my own threads for Core Data" type. - Without seeing your code, my assumption would be the scope within which you create the child context ends and it gets cleaned up.
- When using the parent/child context pattern, you need to be using the block methods. The biggest benefit of using the block methods is that the OS will handle dispatching the method calls to the correct threads. You can use
performBlock
for asynchronous execution, orperformBlockAndWait
for synchronous execution.
You would use this such as:
- (void)saveContexts {
[childContext performBlock:^{
NSError *childError = nil;
if ([childContext save:&childError]) {
[parentContext performBlock:^{
NSError *parentError = nil;
if (![parentContext save:&parentError]) {
NSLog(@"Error saving parent");
}
}];
} else {
NSLog(@"Error saving child");
}
}];
}
Now, you need to keep in mind that changes made in the child context (e.g. Entities inserted) won't be available to the parent context until you save. To the child context, the parent context is the persistent store. When you save, you pass those changes up to the parent, who can then save them to the actual persistent store. Saves propogate changes up one level. On the other hand, fetching into a child context will pull data down through every level (through the parent and into the child)
- You need to use some form of
objectWithID
on the managedObjectContext. They are the safest (and really only) way to pass objects around between contexts. As Tom Harrington mentioned in the comments, you may want to useexistingObjectWithID:error:
though becauseobjectWithID:
always returns an object, even if you pass in an invalid ID (which can lead to exceptions). For more details: Link
Child NSManagedObjectContext update from parent
Fetched results controller needs a main context.
Use this pattern to get rid of the "choppiness".
RootContext (private queue) - saves to persistent store
MainContext (main queue) child of RootContext - use for UI (FRC)
WorkerContext (private queue) - child of MainContext - use for updates & inserts
The your web query is finished, create a worker context and update the data model. When you save
, the changes will be pushed up to the main context and your UI should update via the FRC delegate. Save the main and root context to persist.
Make sure you are using the block methods performBlock
and performBlockAndWait
throughout when dealing with child contexts.
NSManagedObjectContext Child/Parent - Child not removing registeredObjects
When you perform save operation on MOC, It will save the object to parent MOC of persistent store. But object will still retained by MOC in memory.
By default, the references between a managed object and its context are weak. The exception to this rule is that a managed object context maintains a strong reference to any changed (inserted, deleted, and updated) objects until the pending transaction is committed (with a save:) or discarded (with a reset or rollback).
If you feel that this object is no longer need full for current future or alarms are generated (on the fly in a memory store), you would like to trim the graph object by turning every thing into a fault using "refreshObject:object mergeChanges:NO"
Save object from child NSManagedObjectContext not available in parent
Alright, it's a bug! Known bug for many years, but only documented in StackOverflow. The answer is here
https://stackoverflow.com/a/11996957/2073793
One needs to obtain permanent object ids using obtainPermanentIDs(for:)
before saving in the child context. Then, those permanent ObjectIds can be used to retrieve the objects from within the parent context.
Use NSManagedObject in child NSManagedObjectContext instead of its parent
This is where the objectID
property of NSManagedObject
will come in handy.
Ask the object for its ID
let objectID = myManagedObject.objectID
Ask the child context for a managed object with that ID
do {
let childManagedObject = try childContext.existingObjectWithID(objectID)
print("\(newObject)")
} catch {
}
Related Topics
Xctest and Asynchronous Testing in Xcode 6
How to Maintain Presenting View Controller's Orientation When Dismissing Modal View Controller
iOS 8 Tab Bar Item Background Colour
Urlsession.Datatask with Request Block Not Called in Background
Record Audio and Save Permanently in iOS
Change Button Background Color Using Swift Language
App Icons Not Included in Build from Xcode
How to Use Cgaffinetransformmakerotation
Ios: Custom Permission Alert View Text
Nib But Didn't Get a Uitableview
Error: Ld: Library Not Found for -Lpods with Cocoapods
(Swift) Storing and Retrieving Array to Nsuserdefaults
Ld: Framework Not Found Parse Xcode 7 Beta
Rotation Behaving Differently on iOS6
Save Image Data to SQLite Database in Iphone
How to Resize an Image or Done as a Nsattributedstring Nstextattachment (Or Set Its Initital Size)
How Does Square's Cardcase App Automatically Populate the User's Details from the Address Book