【问题标题】:Setting a core data relationship in an NSOperation... The NSManagedObject has been invalidated在 NSOperation 中设置核心数据关系... NSManagedObject 已失效
【发布时间】:2011-04-13 15:13:50
【问题描述】:

我有一个核心数据应用程序,它具有文章和评论的数据结构(一对多关系)。

NSOperations 在不同的线程上管理下载和 JSON 解析,然后它使用 mergeChangesFromContextDidSaveNotification 将更改传递到保存它的主线程,并且 fetchedResultsController 负责 tableView 更改。

对文章和 cmets 的调用在从服务器调用的单独 API 中,每个 API 都有自己的 NSOperation 来处理导入。 (它们大致基于 Apple 的 RSSImporter 类,但已针对 JSON 进行了修改)。每个操作都有自己的上下文并使用 fetchedResultsController 中的 storeCoordinator。

commentParser.articleObjectID = [article objectID];
commentParser.persistentStoreCoordinator = [[self.fetchedResultsController managedObjectContext] persistentStoreCoordinator];

我正在尝试在文章和 cmets 之间的 NSOperation 中设置关系,我相信我通过将文章的 objectID 传递给 cmets 操作,然后通过执行以下操作使用对象来遵循最佳实践:

Article *article = (Article *)[self.insertionContext objectWithID:articleObjectID];
Comment *aComment = (Comment *)[NSEntityDescription insertNewObjectForEntityForName:@"Comment" inManagedObjectContext:self.insertionContext]; 
[aComment setCommentArticle:article];

这似乎工作正常,但是当返回原始文章的 tableView 所在的根 viewController 时,我收到以下错误消息:

* 由于未捕获的异常而终止应用程序 'NSObjectInaccessibleException', 原因:'NSManagedObject 与 ID:0xdb24f30 已失效。'

对此的任何帮助将不胜感激!

【问题讨论】:

    标签: objective-c multithreading core-data concurrency nsoperation


    【解决方案1】:

    您必须将新的核心数据实体(或对现有实体的更改)保存在创建它们的线程(到持久存储)中,然后将对象 ID 传递给主线程,该线程上的 NSManagedContext 将使用objectID 从持久存储中检索对象。

    看看: http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/CoreData/Articles/cdConcurrency.html

    因此,请确保将新对象(或更改的对象)保存到您在后台线程中创建的 NSManagedObjectContext 中,然后一切正常。

    【讨论】:

    • 嗨达米安。谢谢回复!我在操作结束时保存了插入上下文(后台线程 moc),它将通知中的对象传递回主线程,然后合并上下文。因此,而不是使用对象本身。我将 objectID 传回主线程并重新获取?
    • 通常我在 mergeChangesFromContextDidSaveNotification 中处理。您能否发布保存操作以及您如何合并到您的问题中,我将能够提供更有针对性的帮助?
    • 对我来说触发 关注 的部分问题是:NSOperations 在不同的线程上管理下载和 JSON 解析,然后它使用 mergeChangesFromContextDidSaveNotification 将更改传递给主线程它被保存并且 fetchedResultsController 负责 tableView 的更改。
    • 你说你传回了保存它的主线程。您确定要保存在 NSOperation 中吗?
    • 是的。 NSError *saveError = nil; if (![self.insertionContext save:&saveError]) { [ErrorHandler handleError:saveError]; }
    【解决方案2】:

    Damien 让您走上正轨。以下是解决方法:

    1. 主线程上的一个对象注册为NSManagedObjectContextDidSaveNotification

    2. NSOperation 下载 JSON 并将它们添加到在操作中初始化的托管对象上下文中,在添加所有对象后保存上下文。

    3. NSManagedObjectContextDidSaveNotification 通知发生时,请确保您在主线程上处理它。如果没有,将消息转发到主线程上的self。 (有关示例,请参见 Apple 的示例代码 TopSongs)。

    4. 在主线程处理NSManagedObjectContextDidSaveNotification时,调用[context mergeChangesFromContextDidSaveNotification:notification]

    5. 您的 NSFetchedResultsController 会将适当的协议消息发送给它的委托,以便您可以更新您的 UI。

    6. 如果您需要以任何其他方式通知应用中的对象,您可以发布特定于应用的通知,让您的对象可以观察并执行他们需要执行的任何操作。

    您应该将对象 ID 从您的 NSOperation 传递回主线程,然后再次将它们插入到上下文中。你已经在 NSOperation 中做到了。如果您需要知道主线程上的新对象 ID,可以传递并使用它们,但对象已经插入并保存到您的上下文中。

    【讨论】:

    • 只是想补充一点,操作中保存的对象确实出现在我 NSLog'd 的数组中。
    • 保存方法看起来不错。你能在异常发生的地方贴一些代码吗?
    • 调试器在这一行停止了我的 configureCell 函数: Article *article = (Article *)[self.fetchedResultsController objectAtIndexPath:indexPath];这是痕迹。 pastie.org/1791808
    • 我为命名约定道歉,因为两个视图控制器中的两个结果控制器具有相同的名称。这段代码是 newsViewController,它显示了完整的文章列表。
    • 这是一条线索。查找上下文被释放(或未保留)的位置。
    【解决方案3】:

    要检查的一件事:

    在对象被保存到存储之前,ManagedObjectID 只是临时 ID。因此,如果您在保存对象之前获取新创建对象的 ID 并将其交给另一个线程/操作,那么它将只有一个临时 ID,当对象被任何线程/操作实际保存时,该 ID 会更改.

    阅读说明后我不确定,但您可能正在尝试查找具有不再有效的临时 ID 的对象。

    【讨论】:

    • 感谢您的回复。我认为这可能是问题,所以我输入了一个 BOOL 来检查 objectID 是否是临时 ID,但它返回的是永久 ID。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多