I have an NSManagedObjectContext
associated to main thread (mainContext
), where I fetch all the NSManagedObject
I show throughout the
I'm not sure this is a full answer for you but I'm working on a somewhat similar situation. The implementation path I've taken is to use child objects (all over the place) - or more like temporary child context's as needed.
The first thing I should mention, however, is make sure to use the CoreData debug functionality build into XCOde. I made a second Run-Scheme that has
-com.apple.CoreData.ConcurrencyDebug 1
On application init I have my normal NSManagedObjectContext
- which is passed around to my background networking thread.
NSManagedObjectContext *childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[child setParentContext:parentObjectContext];
Then whenever I need to pass something from parent to child I end up doing:
[child objectWithID:(object-in-parent-context)]
or I end up doing
__block AHRS_RPYL * ret;
[[self getChildContext] performBlockAndWait:^{
ret = [NSEntityDescription insertNewObjectForEntityForName:@"RPYL" inManagedObjectContext:[self getChildContext]];
// ... lots of code
}];
I can't say I really "love" this approach and I'm sort of stuck with it for the moment however it does seem to work well enough.
Between most of my view controllers I have a
@synthesize managedObjectContext;
And in my prepareForSegue
method
// Pass on managedObjectContext
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// dispatch_async(dispatch_get_main_queue(), ^{
// If the destination VC is able to take teh setManagedObjectContext method the current objectContext will be passed along.
if ([segue.destinationViewController respondsToSelector:@selector(setManagedObjectContext:)]) {
[segue.destinationViewController performSelector:@selector(setManagedObjectContext:)
withObject:self.managedObjectContext];
} else {
NSLog(@"Segue to controller [%@] that does not support passing managedObjectContext", [segue destinationViewController]);
}
// });
}
CoreData
because no matter how you look at it CoreData
is not the most threading friendly option.I actually save to the child context every 50 messages and to the parent every 250 it looks like (haven't touched this code in ages). I can't promise this is the best correct way to do things but it does work and it does keep disc access to a minimum. I am getting A LOT of messages like 20+ a second so i wanted to do this stack type. You may not care
(self.getChild()) returns the child context - its older code i left here.
if (msgCount % 50 == 0) {
// Child Save!
// NSLog(@"Saving SDatas");
__block NSManagedObjectContext *currentChild = [self getChildContext];
[self incChildContext];
// Parent-Child save methodology
[currentChild performBlock:^{
NSError *error;
if (![currentChild save:&error]) {
NSLog(@"\n error => %@ \n", [error localizedDescription]);
NSLog(@" error => %@ ", [error userInfo]);
[NSException raise:@"Database Write Error" format:@"%@ %@", [error localizedDescription], [error userInfo]];
// abort();
}
if (msgCount % 250 < 5) {
[parentObjectContext performBlock:^{
NSError *error;
if (![parentObjectContext save:&error]) {
NSLog(@"\n error => %@ \n", [error localizedDescription]);
NSLog(@" error => %@ ", [error userInfo]);
[NSException raise:@"Database Write Error" format:@"%@ %@", [error localizedDescription], [error userInfo]];
// abort();
}
}];
}
[currentChild reset];
}];
}
[childContext performBlock:^{
// LOTS OF CODE
// to build a query set of the records we want to kill
// End lots of code
[childContext deleteObject:msg];
if (i % modFactor == 0) {
self.percentDone = i / totalRecords;
NSLog(@"%.1f Saving ...", self.percentDone * 100);
NSError *error;
if (![childContext save:&error]) {
NSLog(@"\n error => %@ \n", [error localizedDescription]);
NSLog(@" error => %@ ", [error userInfo]);
[NSException raise:@"Database Write Error" format:@"%@ %@", [error localizedDescription], [error userInfo]];
// abort();
}
[parentContext performBlock:^{
NSError *errrror;
if (![parentContext save:&errrror]) {
NSLog(@"\n error => %@ \n", [error localizedDescription]);
NSLog(@" error => %@ ", [error userInfo]);
[NSException raise:@"Database Write Error" format:@"%@ %@", [error localizedDescription], [error userInfo]];
// abort();
}
}];
}
}];
Again - like i said before this may not be the best way of doing things but i do have a parent/child stack and it does work. This was one of the first iOS apps I wrote and to do it over again i'd punt on core data and use something else.
We had an extremely high update rate so when we were using a single stack it was making the UI very slow. The migration to parent/child was slow - were i to do it again I think it would have gone smoother because i'd write many helper functions to deal with some of this (or just use swift).
good luck.