将托管对象上下文与 Core Data 中的调度队列一起使用

San*_*dip 0 core-data grand-central-dispatch ios

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

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");
        }
    });
});
Run Code Online (Sandbox Code Playgroud)

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

请让我知道我这样做的方式是否错误,因为理想情况下我无法从主线程保存后台线程的 MOC。

谢谢你。

War*_*ton 5

它是错误的,因为它的线程不安全而不是线程不可能与上下文和托管对象交叉线程。

因此,您的微不足道的示例可能在某些情况下有效,但并非在所有情况下都有效。迟早你会遇到这种模式的崩溃。

如果您希望在线程之间访问对象,则必须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;

            });
        }

    }];
Run Code Online (Sandbox Code Playgroud)

  • @qullish 我想要来自主线程上下文的对象,以便我可以在主线程上更新 UI。如果在私有队列中通过 ID 恢复对象,则会导致无法实现的错误和悲伤。 (2认同)