Closed chbeer closed 11 years ago
Hi Christian, sorry for the delay in responding, we were shipping a new app last week. :smiley:
MoneyWell uses UIManagedDocument which has an NSPrivateQueueConcurrencyType managed object context as the root context that handles all read and writes to the persistent store and an NSMainQueueConcurrencyType managed object context as the application's main context. When configuring our document sync manager via
- (void)configureWithDelegate:(id <TICDSDocumentSyncManagerDelegate>)aDelegate appSyncManager:(TICDSApplicationSyncManager *)anAppSyncManager managedObjectContext:(NSManagedObjectContext *)aContext documentIdentifier:(NSString *)aDocumentIdentifier description:(NSString *)aDocumentDescription userInfo:(NSDictionary *)someUserInfo;
We pass that main queue concurrency type MOC as the managedObjectContext and mark it as synchronized. For us that looks like this, where the MWISyncActionController handles all our communication with TICDS:
self.managedDocument.managedObjectContext.synchronized = YES;
[[MWISyncActionController sharedSyncActionController] preconfigureSyncWithManagedObjectContext:self.managedDocument.managedObjectContext];
From there, any time the framework kicks off a TICDSSynchronizationOperation it creates its own child context with the application's MOC as its parent:
// TICDSSynchronizationOperation.m line 1333
- (TICDSSynchronizationOperationManagedObjectContext *)backgroundApplicationContext
{
if (_backgroundApplicationContext) {
return _backgroundApplicationContext;
}
_backgroundApplicationContext = [[TICDSSynchronizationOperationManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_backgroundApplicationContext performBlockAndWait:^{
_backgroundApplicationContext.parentContext = self.primaryManagedObjectContext;
[_backgroundApplicationContext setUndoManager:nil];
}];
[[NSNotificationCenter defaultCenter] addObserver:[self delegate] selector:@selector(backgroundManagedObjectContextDidSave:) name:NSManagedObjectContextDidSaveNotification object:_backgroundApplicationContext];
return _backgroundApplicationContext;
}
All sync changes are applied to this background context which is then saved to push those changes automatically up to the main application context.
Where you might be seeing a lot of main thread MOC activity is if you're still manually merging changes in from an NSManagedObjectContextDidSaveNotification. This step is no longer necessary with parent/child contexts. The changes made by the child are automatically pushed to the parent when the child saves. The best part is that it's super fast.
Let me know if that clears things up for you.
Good Morning Michael,
thanks a lot for the information.
I currently only have one main context with NSMainQueueConcurrencyType
that I set to be synchronized. What helped to improve the performance was to remove the commented line:
- (void)documentSyncManager:(TICDSDocumentSyncManager *)aSyncManager didMakeChangesToObjectsInBackgroundContextAndSaveWithNotification:(NSNotification *)aNotification
{
// [[self managedObjectContext] mergeChangesFromContextDidSaveNotification:aNotification];
}
Do you think having a NSPrivateQueueConcurrencyType
context in the background would be better, performance wise? As it can do the "hard work" in the background?
Check out the documentation on UIManagedDocument. The big benefit is that the private queue parent context allows for asynchronous writing to disk, so the main thread is never blocked by a data save.
And yes, commenting out the mergeChangesFromContextDidSaveNotification:
call is exactly what I was talking about.
Thanks a lot, Michael, for clearing that up. I'll have a look at that documentation.
Quick question: This issue refers to a "parent-child-conversion branch" -- where is this branch? I can't find this in the code.
That branch has been merged into master.
Hi Michael,
again mis-using this for a question. But this way all other users can see it as well.
Regarding the switch to parent-child managed object context: how do you structure the hierarchy?
I currently have set the NSMainQueueConcurrencyType-context to be synchronized. That leads to much work be done on the main thread by TICoreDataSync (or Core Data) when syncing changes.
Should I have a top-level managed object context that gets synched and a NSMainQueueConcurrencyType sub-context? In my tests this led to missing updates?
I merged your parent-child-conversion branch with Drew's extension for iCloud which works great so far.
Thanks and best regards,
Christian