在Core Data中使用托管对象上下文和Dispatch队列

时间:2014-08-29 11:55:17

标签: ios core-data grand-central-dispatch

根据苹果指南,为了在主线程上使用托管对象,它们只需要被限制在主线程中的上下文获取,好吧没关系。以下是我的代码......

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");
        }
    });
});

现在根据指南,我无法修改或保存由另一个线程创建的托管对象上下文。但上面的代码工作正常,修改和保存我的对象没有任何错误。因此,我能够修改由另一个线程获取的MO,甚至可以保存由另一个线程创建的MOC。

如果我这样做的方式是错误的,请告诉我,因为理想情况下我无法从主线程中保存背景线程的MOC。

谢谢。

1 个答案:

答案 0 :(得分:4)

它错了,因为它的线程不安全的NOT线程无法与上下文和托管对象交叉线程。

所以你的琐碎例子可能会在某些时候起作用,但在所有情况下都不是全部。迟早你会遇到这种模式的崩溃。

如果您希望在线程之间访问对象,则必须在线程中发送objectID

当您使用NSPrivateQueueConcurrencyType创建上下文时,它会创建并管理自己的队列。

你的例子更好地表达为

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;

            });
        }

    }];