Reputation: 176
According to apple guideline, In order to use managed objects on the main thread, they need to be fetched by a context confined to the main thread only ,Ok thats fine. Below is my code...
AppDelegate *del = [[UIApplication sharedApplication] delegate];
dispatch_queue_t queue1 = dispatch_queue_create("com.MyApp.AppTask",NULL);
dispatch_queue_t main = dispatch_get_main_queue();
dispatch_async(queue1, ^{
NSManagedObjectContext *workerContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
workerContext.persistentStoreCoordinator = del.persistentStoreCoordinator;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
NSArray *managedObject = [workerContext executeFetchRequest:fetchRequest error:nil];
dispatch_async(main, ^{
NSLog(@"%@",managedObject);
Person *objperson = [managedObject objectAtIndex:0];
objperson.firstname = @“test”;
BOOL s = [workerContext save:nil];
if (s) {
NSLog(@"done");
}
});
});
Now as per the guideline I can not modify or save managed object context created by another thread. But above code works fine and modify and save my object without any error. Hence I am able to modify the MO which is fetched by another thread and even I can save MOC which is created by another thread.
Please let me know if my way of doing this is wrong or not because ideally i could not save MOC of Background thread from main thread.
thank you.
Upvotes: 0
Views: 3782
Reputation: 17372
Its wrong because its thread-unsafe NOT thread impossible to cross threads with contexts and managed objects.
So your trivial example might work some of the time but not all of time in all situations. Sooner or later you are going to get a crash with that pattern.
if you wish to access objects between threads you must send the objectID
across the thread.
When you create a context with NSPrivateQueueConcurrencyType
it creates and manages its own queue.
Your example is expressed better as
AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *workerContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
//set the parent NOT the persistent store coordinator
workerContext.parentContext = delegate.managedObjectContext;
[workerContext performBlock:^{
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
NSArray *results = [workerContext executeFetchRequest:fetchRequest error:nil];
if (results.count) {
Person *person = [results objectAtIndex:0];
person.firstname = @“test”;
BOOL success = [workerContext save:nil];
if (success) {
NSLog(@"done");
}
//you pass ObjectID's NOT managed objects across threads
NSManagedObjectID *objectID = [person objectID];
dispatch_async(dispatch_get_main_queue(), ^{
//update your UI here
Person *thePerson = (Person *)[[delegate managedObjectContext] objectWithID:objectID];
self.myUIElement.text = person.firstname;
});
}
}];
Upvotes: 5