多线程 – 为什么在NSOperation子类中修改Core Data关系时,我的应用程序崩溃?

前端之家收集整理的这篇文章主要介绍了多线程 – 为什么在NSOperation子类中修改Core Data关系时,我的应用程序崩溃?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
背景

我有以下对象树:

  1. Name Project
  2. Users nil
  3. John nil
  4. Documents nil
  5. Acme Project Acme Project <--- User selects a project
  6. Proposal.doc Acme Project
  7. 12:32-12:33 Acme Project
  8. 13:11-13:33 Acme Project
  9. ...thousands more entries here...

>用户可以为一个项目分配一个组.所有后代都被设置为该项目.
>这会锁定主线程,所以我使用NSOperations.
>我正在使用Apple批准的这种方法,看NSManagedObjectContextDidSaveNotification并合并到主要的上下文中.

问题

我的保存已经失败,出现以下错误

保存前无法处理挂起的更改. 100次尝试后,上下文仍然很脏.通常这个递归的脏污是由一个坏的验证方法,-willSave或通知处理程序引起的.

我试过的

我已经把我的应用程序的所有复杂性都消除掉了,并且做了我能想到的最简单的项目.并且错误仍然发生.我试过了:

>将队列上的最大操作数设置为1或10.
>调用refreshObject:mergeChanges:在NSOperation子类的几个点.
>在受管对象上下文中设置合并策略.
>建立和分析.它变空了

我的问题

没有我的应用程序崩溃,我如何在NSOperation中设置关系?当然这不是Core Data的限制吗?它可以?

代码

下载我的项目:http://synapticmishap.co.uk/CDMTTest1.zip

主控制器

  1. @implementation JGMainController
  2.  
  3. -(IBAction)startTest:(id)sender {
  4. NSManagedObjectContext *imoc = [[NSApp delegate] managedObjectContext];
  5.  
  6. JGProject *newProject = [JGProject insertInManagedObjectContext:imoc];
  7. [newProject setProjectName:@"Project"];
  8. [imoc save];
  9.  
  10. // Make an Operation Queue
  11. NSOperationQueue *queue = [[NSOperationQueue alloc] init];
  12. [queue setMaxConcurrentOperationCount:1]; // Also crashes with a higher number here (unsurprisingly)
  13.  
  14. NSSet *allTrainingGroupsSet = [imoc fetchAllObjectsForEntityName:@"TrainingGroup"];
  15.  
  16. for(JGTrainingGroup *thisTrainingGroup in allTrainingGroupsSet) {
  17. JGMakeRelationship *makeRelationshipOperation = [[JGMakeRelationship alloc] trainGroup:[thisTrainingGroup objectID] withProject:[newProject objectID]];
  18. [queue addOperation:makeRelationshipOperation];
  19. makeRelationshipOperation = nil;
  20. }
  21. }
  22.  
  23. // Called on app launch.
  24. -(void)setupLotsOfTestData {
  25. // Sets up 10000 groups and one project
  26. }
  27.  
  28. @end

进行关系操作

  1. @implementation JGMakeRelationshipOperation
  2.  
  3. -(id)trainGroup:(NSManagedObjectID *)groupObjectID_ withProject:(NSManagedObjectID *)projectObjectID_ {
  4. appDelegate = [NSApp delegate];
  5. imoc = [[NSManagedObjectContext alloc] init];
  6. [imoc setPersistentStoreCoordinator:[appDelegate persistentStoreCoordinator]];
  7. [imoc setUndoManager:nil];
  8. [imoc setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy];
  9.  
  10. [[NSNotificationCenter defaultCenter] addObserver:self
  11. selector:@selector(mergeChanges:)
  12. name:NSManagedObjectContextDidSaveNotification
  13. object:imoc];
  14. groupObjectID = groupObjectID_;
  15. projectObjectID = projectObjectID_;
  16. return self;
  17. }
  18.  
  19. -(void)main {
  20. JGProject *project = (JGProject *)[imoc objectWithID:projectObjectID];
  21. JGTrainingGroup *trainingGroup = (JGTrainingGroup *)[imoc objectWithID:groupObjectID];
  22. [project addGroupsAssignedObject:trainingGroup];
  23. [imoc save];
  24.  
  25. trainingGroupObjectIDs = nil;
  26. projectObjectID = nil;
  27. project = nil;
  28. trainingGroup = nil;
  29. }
  30.  
  31. -(void)mergeChanges:(NSNotification *)notification {
  32. NSManagedObjectContext *mainContext = [appDelegate managedObjectContext];
  33. [mainContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:)
  34. withObject:notification
  35. waitUntilDone:YES];
  36. }
  37.  
  38. -(void)finalize {
  39. appDelegate = nil;
  40. [[NSNotificationCenter defaultCenter] removeObserver:self];
  41. imoc = nil;
  42. [super finalize];
  43. }
  44. @end
  45.  
  46.  
  47. @implementation NSManagedObjectContext (JGUtilities)
  48.  
  49. -(BOOL)save {
  50. // If there's an save error,I throw an exception
  51. }
  52.  
  53. @end

数据模型

更新1

我已经尝试了一些,即使没有合并,仍然抛出异常.修改关系后,只需将管理对象上下文保存在另一个线程就足够了.

我有一个共享的持久性商店协调员与应用程序代表.我已经尝试为线程使用与数据存储相同的URL创建一个单独的NSPersistentStoreCoordinator,但是Core Data抱怨.

我很乐意提供关于如何使线程的协调者的建议.核心数据文件提到有一种方法,但我看不到如何.

解决方法

你正在跨越在CoreData中非常糟糕的流(在这种情况下是线程).这样看看:

startTest从一个按钮调用(是IBAction,假设按钮点击)在主线程上
>您的for循环使用初始化程序trainGroup创建一个JGMakeRelationship对象:withProject:(这应该称为init,并且可能调用super,但这不会导致此问题).
>在主线程中,在操作中创建一个新的托管对象上下文.
>现在操作队列从工作线程调用操作“main”方法(在这里放置一个断点,你会看到它不在主线程上).
>您的应用程序变得繁荣,因为您已经从与其创建的线程不同的线程访问了受管对象上下文.

解:

在操作的main方法中初始化托管对象上下文.

猜你在找的Java相关文章