1

正如标题所暗示的,我正在使用一个核心数据应用程序,该应用程序在不同的后台线程中填充了对象(XML 解析)

在我的后台线程中,我正在这样做

managedContext = [[NSManagedObjectContext alloc] init];
[managedContext setUndoManager:nil];

[managedContext setPersistentStoreCoordinator: [[DataManager sharedManager] persistentStoreCoordinator]];

 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 
 [nc addObserver:self
        selector:@selector(mergeChanges:)
            name:NSManagedObjectContextDidSaveNotification
          object:managedContext];


NSMutableArray *returnSource = [[self parseDocument:doc] retain];


 [managedContext save:&error];

 if (error) {
     NSLog(@"saving error in datafeed"); 
 }

 [managedContext reset];

[self performSelectorOnMainThread:@selector(parseCompleteWithSource:) withObject:returnSource waitUntilDone:YES];

Merge 方法如下所示:

NSManagedObjectContext *mainContext = [[DataManager sharedManager] managedObjectContext];

// Merge changes into the main context on the main thread
[mainContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:)
                              withObject:notification
                           waitUntilDone:YES];  

[[NSNotificationCenter defaultCenter] removeObserver:self];

我认为合并是成功的,但是因为我想在 UITableView 中显示它,所以它总是告诉我我的对象无效,这是可以预期的,因为

[managedContext reset];

我想要做的是显示当前在数据库中的项目,在后台解析 xml,如果完成,我想用新的/更新的对象更新 UITableView。我将如何做到这一点,我可以以某种方式将对象“更新”到另一个 Context 还是合并无法正常工作?

我需要在 Main ObjectContext 中定义一些特定的东西吗?我尝试了不同的合并策略,但没有任何运气。

希望你能帮助我,谢谢!

4

2 回答 2

3

我相信你的问题是returnSource数组的内容。如果那是一堆NSManagedObject实例,那么它们将由后台线程上下文在后台线程上创建。

您调用 to-[NSManagedObjectContext reset]将使它们无效,因为这是您明确告诉上下文要做的事情。但这不是大问题。

然后,您继续将数组发送到主线程,通过NSManagedObject线程边界传递实例,并且在上下文之间是一个很大的禁忌。

你需要做的是:

  1. NSManagedObjectID用s 的 s创建一个数组NSManagedObject
  2. 通过线程边界发送对象 ID 数组。
  3. NSManagedObject使用它的上下文在新线程上从托管对象 ID重新创建一个带有 s 的数组。

我做了一些核心数据助手,遵循三规则(第三次你写东西,让它通用)

最重要的是,我隐藏了为每个线程管理不同托管对象上下文、处理通知和所有垃圾的复杂性。相反,我介绍了线程本地上下文的概念。基本上是惰性创建NSManagedObjectContext的实例,当当前线程退出时会自动注册更新和清理。

一个正常的用例:

NSManagedObjectCotext* context = [NSManagedObjectCotext threadLocalContext];
// Do your stuff!!
NSError* error = nil;
if (![context saveWithFailureOption:NSManagedObjectContextCWSaveFailureOptionThreadDefault 
                              error:&error]) 
{
    // Handle error.
}

完整的源代码,包括用于解析来自 apple.com 的新闻 RSS 并将其存储在 Core Data 中的示例应用程序,可在此处获得:https ://github.com/jayway/CWCoreData 。

于 2011-07-26T18:21:55.150 回答
1

在这种情况下没有理由调用reset后台上下文,因为无论如何它都会随着后台线程而消失,并且您在任何情况下都不会再次使用它。reset当您希望上下文忘记之前的步骤时,通常使用撤消管理。

您的主要问题是您的后台线程配置为从它创建的托管对象上下文接收通知。那是相当没有意义的。

相反,您需要注册 tableview 控制器(在前端线程上)以NSManagedObjectContextDidSaveNotification从后台线程的上下文中接收。这样,当后台上下文保存时,前端/主上下文将使用新数据更新自身,这将触发 tableview 的更新。

于 2011-07-26T16:09:28.913 回答