帮助多线程核心数据应用程序设计

7

alt text

上图是我模型的简化版。我的应用程序有一个NSWindowController对象,控制两个NSViewController对象,分别用于用户账户实体。当用户登录应用程序时,他们可以通过调用相关的视图控制器来修改用户或账户信息。在后台,我让应用程序定期在单独的线程上填充用户日志。

我正在为后台线程使用单独的NSManagedObjectContext,并为视图控制器中的数据输入使用应用程序委托的NSManagedObjectContext。我想知道以下几点:

1)这种做法好吗?我应该为每个视图控制器创建一个NSManagedObjectContext,然后在用户完成更改后合并上下文吗?

2)因为日志实体是在后台线程中创建的,它有自己的NSManagedObjectContext。然而,每个日志都包括来自应用程序委托的用户账户实体的信息。这是如何获取用户的:

- (NSManagedObjectID*) fetchUser:(NSString*) userID {   
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];   
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"user":inManagedObjectContext:self.managedObjectContext];
    /** snip **/
}

这个方法将被后台线程按以下方式调用:
NSManagedObjectID* userObjectID = [self fetchUser:userID];
NSManagedObject* userObject = [self.logsManagedObjectContext objectWithID:userObjectID];

我正在执行的fetchUser是否线程安全?在获取用户时,我需要锁定主要的管理对象上下文以防止其中一个视图修改同一用户吗?从这篇文章中,我了解到(也许不正确),我可能需要这样做。到目前为止,我还没有遇到任何问题,但我不想留下潜在的边缘情况。
3)当其中一个视图控制器更改应用程序委托的NSManagedObjectContext时,它会发布一个通知,如下所示处理:
- (void)contextDidSave:(NSNotification *)notification {
    SEL selector = @selector(mergeChangesFromContextDidSaveNotification:);
    [self.logManagedObectContext performSelector:selector onThread:backgroundThread withObject:notification waitUntilDone:NO];
}

我应该如何处理合并操作?是应该合并应用程序代理的NSManagedObjectContext还是其他方式?我发现这样做(在主线程上)会锁定用户界面。

任何帮助将不胜感激。

1个回答

9

NSManagedObjectContext 对象不支持多线程。这意味着,如果你希望从多个线程访问 Core Data,则需要为每个线程创建一个NSManagedObjectContext对象,并在该线程上创建它。每个对象都可以使用相同的NSPersistentStoreCoordinator,后者将序列化对持久存储的访问。

这是因为每个NSManagedObjectContext 在使用时知道如何正确地锁定NSPersistentStoreCoordinator,以避免冲突。按照这些规则,你应该保持线程安全。

就像你已经在做的那样,应该使用NSManagedObjectID来传递 Core Data 对象从一个MOC到另一个MOC(并且从一个线程到另一个线程)。但是你正在调用fetchUser:,它使用主线程的MOC,在后台线程上运行。这是不正确的。必须从主线程调用那个fetchUser:方法。当然,这并不能阻止你使用后台 MOC 在后台线程中检索用户。

总之,始终要在创建它的线程中调用NSManagedObjectContext的方法。

这里的诀窍是确保两个 MOC 都知道另一个的保存情况,因此你必须注册以从每个上下文接收通知。然后,你应该为 MOC 的适当线程执行mergeChangesFromContextDidSaveNotification:。目前,你正在通知主线程的 MOC 更改,但不是反过来。

噢,而且没有必要为每个NSViewController创建单独的上下文。作为 UI 元素,他们与上下文的交互将在同一个(主)线程上发生,因此共享是可以的。


我不知道我可以从后台MOC中检索用户。我所需要做的就是给他们相同的NSPersistentStoreCoordinator?如果我这样做,我需要使用Object ID检索还是可以直接获取对象? - David
你可以直接获取对象。只需编写代码以在共享同一协调器的任何其他 MOC 收到通知时合并更改即可。 - paulbailey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接