帮助设计多线程 Core Data 应用程序

发布于 2024-10-08 06:02:01 字数 1911 浏览 0 评论 0原文

alt text

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

我使用单独的 NSManagedObjectContext 作为后台线程,并使用应用程序委托的 NSManagedObjectContext 用于视图控制器中的数据输入。我想知道一些事情:

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

2) 因为log实体是在后台线程中创建的,所以它有自己的NSManagedObjectContext。但是,每个日志都包含来自用户帐户实体的信息,这些实体是在应用程序委托的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 而是?我发现这样做(在主线程上)会锁定 UI。

任何帮助将不胜感激。

alt text

Above is a simplification of what my model looks like. My app has a NSWindowController object controlling two NSViewController objects for the user and account entities. When a user logs in to the app, they can modify user or account information by bringing up the relevant view controller. In the background I have the application periodically populating the user's logs in the application delegate on a separate thread.

I am using a separate NSManagedObjectContext for the background thread and the application delegate's NSManagedObjectContext for data entry in the view controllers. I would like to know a few things:

1) is this good practice? Should I create a NSManagedObjectContext for each view controller and then merge the contexts whenever the user is done making changes?

2) Because the log entity is created in the background thread, it has it's own NSManagedObjectContext. However, each log includes information from the user and account entities, which are created in the application delegate's NSManagedObjectContext. This is how I am fetching a user:

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

This method is called by the background thread as follows:

NSManagedObjectID* userObjectID = [self fetchUser:userID];
NSManagedObject* userObject = [self.logsManagedObjectContext objectWithID:userObjectID];

Is what I'm doing in fetchUser thread-safe? Do I need to lock the main managed object context while fetching a user in case one of the views is modifying the same user? From this article I understand (perhaps incorrectly) that I may have to do so. So far I haven't run into any problems but I don't want to leave a potential edge case.

3) When one of the view controllers makes changes to the application delegate's NSManagedObjectContext it posts a notification that is handled as follows:

- (void)contextDidSave:(NSNotification *)notification {
    SEL selector = @selector(mergeChangesFromContextDidSaveNotification:);
    [self.logManagedObectContext performSelector:selector onThread:backgroundThread withObject:notification waitUntilDone:NO];
}

Is this how I should handle the merge or should I be merging the application delegate's NSManagedObjectContext instead? I found that doing that (on the main thread) locked up the UI.

Any help will be appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

不即不离 2024-10-15 06:02:01

NSManagedObjectContext 对象不是线程安全的。这意味着,如果您希望从多个线程访问核心数据,则每个线程都需要一个(并且也在该线程上创建)。其中每个都可以使用相同的 NSPercientStoreCoordinator,它将序列化对持久存储的访问。

发生这种情况是因为每个 NSManagedObjectContext 知道如何在使用时正确锁定 NSPersistentStoreCoordinator,从而避免冲突。通过遵循这些规则,您应该保持线程安全。

正如您已经在做的那样,NSManagedObjectID 对象应该用于将核心数据对象从一个 MOC 传递到另一个 MOC(以及通过从一个线程扩展到另一个线程)。但是,您正在调用 fetchUser: ,它在后台线程上使用主线程中的 MOC。这是不正确的。该 fetchUser: 方法调用必须从主线程调用。当然,没有什么可以阻止您使用后台 MOC 在后台线程中检索用户。

总之,始终从创建 NSManagedObjectContext 的线程中调用它。

这里的技巧是确保两个 MOC 都知道对方的保存,因此您必须注册才能接收来自每个 MOC 的通知语境。然后,您应该从 MOC 的适当线程执行 mergeChangesFromContextDidSaveNotification:。目前,您的后台上下文正在收到有关主线程上下文的更改的通知,但反之则不然。

哦,并且不需要为每个 NSViewController 拥有单独的上下文。作为 UI 元素,它们与上下文的交互将发生在同一(主)线程上,因此共享是可以的。

NSManagedObjectContext objects are not thread-safe. This means that if you wish to access Core Data from multiple threads, you will need one for each thread (and created on the thread too). Each of these can use the same NSPersistentStoreCoordinator, which will serialise access to the persistent store.

This occurs because each NSManagedObjectContext knows how to properly lock the NSPersistentStoreCoordinator when it is in use, avoiding collisions. By following these rules, you should remain thread-safe.

As you're already doing, NSManagedObjectID objects should be used to pass Core Data objects from one MOC to another (and by extension from one thread to another). However you are calling fetchUser: which uses the MOC from your main thread, on a background one. This isn't correct. That fetchUser: method call must be called from the main thread. Of course, there's nothing to stop you from retrieving the user in the background thread using the background MOC.

In summary, always make calls to an NSManagedObjectContext from the thread it was created in.

The trick here is to make sure that both MOCs know about the other's saves, so you must register to receive the notifications from each context. You should then be performing the mergeChangesFromContextDidSaveNotification: from the appropriate thread for the MOC. At the moment, your background context is being notified about changes from the main thread's context, but not vice versa.

Oh, and there's no need to have a separate context for each NSViewController. As UI elements, their interactions with the context will occur on the same (main) thread, so sharing is fine.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文