在 NSOperation 中设置核心数据关系... NSManagedObject 已失效
我有一个核心数据应用程序,其数据结构为文章和文章。注释(一对多关系)。
NSOperations 在不同的线程上管理下载和 JSON 解析,然后使用 mergeChangesFromContextDidSaveNotification 将更改传递到保存更改的主线程,并由 fetchedResultsController 处理 tableView 更改。
对文章和评论的调用位于从服务器调用的单独 API 中,每个 API 都有自己的 NSOperation 来处理导入。 (它们大致基于 Apple 的 RSSImporter 类,但已针对 JSON 进行了修改)。每个操作都有自己的上下文,并使用 fetchedResultsController 中的 storeCoordinator。
commentParser.articleObjectID = [article objectID];
commentParser.persistentStoreCoordinator = [[self.fetchedResultsController managedObjectContext] persistentStoreCoordinator];
我正在尝试在 NSOperation 中设置文章和评论之间的关系,并且我相信我正在遵循最佳实践,将文章的 objectID 传递到评论操作中,然后通过执行以下操作来使用该对象:
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 已失效。'
任何对此的帮助将不胜感激!
I have a Core Data application which has a data structure of Articles & Comments (One to many relationship).
NSOperations manage the download and JSON parsing on a different thread then it uses mergeChangesFromContextDidSaveNotification to pass the changes to main thread where it's saved and a fetchedResultsController takes care of the tableView changes.
The calls for the articles and comments are in separate APIs called from the server and each has it's own NSOperation to handle the import. (They are based loosely around Apple's RSSImporter class but have been modified for JSON). Each operation has it's own context and uses the storeCoordinator from the fetchedResultsController.
commentParser.articleObjectID = [article objectID];
commentParser.persistentStoreCoordinator = [[self.fetchedResultsController managedObjectContext] persistentStoreCoordinator];
I'm trying to set the relationship in the NSOperation between the article and the comments and I believe I'm following the best practices by passing the objectID of the article into the comments operation and then using the object by doing the following:
Article *article = (Article *)[self.insertionContext objectWithID:articleObjectID];
Comment *aComment = (Comment *)[NSEntityDescription insertNewObjectForEntityForName:@"Comment" inManagedObjectContext:self.insertionContext];
[aComment setCommentArticle:article];
This seems to work fine but when going back to the root viewController where the tableView of original articles are, I'm getting the following error message:
* Terminating app due to uncaught exception
'NSObjectInaccessibleException',
reason: 'The NSManagedObject with
ID:0xdb24f30has been invalidated.'
Any help with this would be appreciated!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您必须将新的核心数据实体(或对现有实体的更改)保存在创建它们的线程中(保存到持久存储),然后将对象 ID 传递到主线程,其中该线程上的 NSManagedContext 将使用 objectID 来检索来自持久存储的对象。
看看:
http://developer.apple.com/ library/ios/#documentation/cocoa/conceptual/CoreData/Articles/cdConcurrency.html
因此,请确保将新对象(或更改的对象)保存到您创建的 NSManagedObjectContext在后台线程中,然后一切都应该正常工作。
You must save the new Core Data entities (or changes to existing ones) in the thread that creates them (to the persistent store) and then pass the object ID's out to your main thread where the NSManagedContext on that thread will use the objectID to retrieve the objects from the persistent store.
Have look at:
http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/CoreData/Articles/cdConcurrency.html
So make sure you are saving the new objects (or changed objects) to the NSManagedObjectContext you created in the background thread and then everything should work fine.
达米安让你走上正轨。解决方法如下:
主线程上的一个对象已注册
NSManagedObjectContextDidSaveNotification
NSOperation
下载 JSON 并将它们添加到操作中初始化的托管对象上下文中,并在添加所有对象后保存上下文。当发生
NSManagedObjectContextDidSaveNotification
通知时,请确保您在主线程上处理它。如果没有,则将消息转发到主线程上的self
。 (有关示例,请参阅 Apple 的示例代码TopSongs
)。在主线程上处理
NSManagedObjectContextDidSaveNotification
时,调用[context mergeChangesFromContextDidSaveNotification:notification]
。您的
NSFetchedResultsController
将向其委托发送适当的协议消息,以便您可以更新 UI。如果您需要以任何其他方式通知应用中的对象,您可以发布特定于应用的通知,您的对象可以观察并执行它们需要执行的任何操作。
您不应该不将对象 ID 从 NSOperation 传递回主线程,然后再次将它们插入到上下文中。您已经在 NSOperation 中做到了这一点。如果您需要知道主线程上的新对象 ID,可以传递并使用它们,但对象已经插入并保存到您的上下文中。
Damien's got you on the right track. Here's how to approach this:
An object on your main thread is registered for
NSManagedObjectContextDidSaveNotification
The
NSOperation
downloads the JSON and adds them to a managed object context initialized within the operation, saving the context when all objects have been added.When the
NSManagedObjectContextDidSaveNotification
notification occurs, make sure that you are handling it on the main thread. If not, forward the message toself
on the main thread. (see Apple's sample codeTopSongs
for an example).When handling
NSManagedObjectContextDidSaveNotification
on the main thread, call[context mergeChangesFromContextDidSaveNotification:notification]
.Your
NSFetchedResultsController
will send the appropriate protocol messages to its delegate so you can update your UI.If you need to notify objects in your app in any other way, you can post an app specific notification that your objects can observe and do whatever they need to do.
You should NOT pass the object IDs back from your NSOperation to the main thread and insert them into the context again. You already did that in the NSOperation. If you need to know the new object IDs on your main thread that's fine to pass them and use them, but the objects have already been inserted and saved to your context.
需要检查的一件事是:
在将对象保存到存储之前,ManagedObjectID 只是临时 ID。因此,如果您在保存对象之前获取新创建对象的 ID 并将其传递给另一个线程/操作,那么它将只有一个临时 ID,当任何线程/操作实际保存该对象时,该 ID 都会发生变化。
通过阅读描述我不确定,但您可能正在尝试查找具有不再有效的临时 ID 的对象。
One thing to check:
ManagedObjectIDs are just temporary IDs until the object is saved to a store. So, if you take an ID of a newly created object and hand it off to another thread/operation before the object has been saved, then it will have only a temporary ID which will change when the object is actually saved by any thread/operation.
I'm not sure from reading the description but it is likely that you are trying to find an object with a temporary ID that is no longer valid.