我有以下对象树:
Name Project Users nil John nil Documents nil Acme Project Acme Project <--- User selects a project Proposal.doc Acme Project 12:32-12:33 Acme Project 13:11-13:33 Acme Project ...thousands more entries here...
>用户可以为一个项目分配一个组.所有后代都被设置为该项目.
>这会锁定主线程,所以我使用NSOperations.
>我正在使用Apple批准的这种方法,看NSManagedObjectContextDidSaveNotification并合并到主要的上下文中.
问题
我的保存已经失败,出现以下错误:
保存前无法处理挂起的更改. 100次尝试后,上下文仍然很脏.通常这个递归的脏污是由一个坏的验证方法,-willSave或通知处理程序引起的.
我试过的
我已经把我的应用程序的所有复杂性都消除掉了,并且做了我能想到的最简单的项目.并且错误仍然发生.我试过了:
>将队列上的最大操作数设置为1或10.
>调用refreshObject:mergeChanges:在NSOperation子类的几个点.
>在受管对象上下文中设置合并策略.
>建立和分析.它变空了
我的问题
没有我的应用程序崩溃,我如何在NSOperation中设置关系?当然这不是Core Data的限制吗?它可以?
下载我的项目:http://synapticmishap.co.uk/CDMTTest1.zip
主控制器
@implementation JGMainController -(IBAction)startTest:(id)sender { NSManagedObjectContext *imoc = [[NSApp delegate] managedObjectContext]; JGProject *newProject = [JGProject insertInManagedObjectContext:imoc]; [newProject setProjectName:@"Project"]; [imoc save]; // Make an Operation Queue NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue setMaxConcurrentOperationCount:1]; // Also crashes with a higher number here (unsurprisingly) NSSet *allTrainingGroupsSet = [imoc fetchAllObjectsForEntityName:@"TrainingGroup"]; for(JGTrainingGroup *thisTrainingGroup in allTrainingGroupsSet) { JGMakeRelationship *makeRelationshipOperation = [[JGMakeRelationship alloc] trainGroup:[thisTrainingGroup objectID] withProject:[newProject objectID]]; [queue addOperation:makeRelationshipOperation]; makeRelationshipOperation = nil; } } // Called on app launch. -(void)setupLotsOfTestData { // Sets up 10000 groups and one project } @end
进行关系操作
@implementation JGMakeRelationshipOperation -(id)trainGroup:(NSManagedObjectID *)groupObjectID_ withProject:(NSManagedObjectID *)projectObjectID_ { appDelegate = [NSApp delegate]; imoc = [[NSManagedObjectContext alloc] init]; [imoc setPersistentStoreCoordinator:[appDelegate persistentStoreCoordinator]]; [imoc setUndoManager:nil]; [imoc setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeChanges:) name:NSManagedObjectContextDidSaveNotification object:imoc]; groupObjectID = groupObjectID_; projectObjectID = projectObjectID_; return self; } -(void)main { JGProject *project = (JGProject *)[imoc objectWithID:projectObjectID]; JGTrainingGroup *trainingGroup = (JGTrainingGroup *)[imoc objectWithID:groupObjectID]; [project addGroupsAssignedObject:trainingGroup]; [imoc save]; trainingGroupObjectIDs = nil; projectObjectID = nil; project = nil; trainingGroup = nil; } -(void)mergeChanges:(NSNotification *)notification { NSManagedObjectContext *mainContext = [appDelegate managedObjectContext]; [mainContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:) withObject:notification waitUntilDone:YES]; } -(void)finalize { appDelegate = nil; [[NSNotificationCenter defaultCenter] removeObserver:self]; imoc = nil; [super finalize]; } @end @implementation NSManagedObjectContext (JGUtilities) -(BOOL)save { // If there's an save error,I throw an exception } @end
数据模型
更新1
我已经尝试了一些,即使没有合并,仍然抛出异常.修改关系后,只需将管理对象上下文保存在另一个线程就足够了.
我有一个共享的持久性商店协调员与应用程序代表.我已经尝试为线程使用与数据存储相同的URL创建一个单独的NSPersistentStoreCoordinator,但是Core Data抱怨.
解决方法
startTest从一个按钮调用(是IBAction,假设按钮点击)在主线程上
>您的for循环使用初始化程序trainGroup创建一个JGMakeRelationship对象:withProject:(这应该称为init,并且可能调用super,但这不会导致此问题).
>在主线程中,在操作中创建一个新的托管对象上下文.
>现在操作队列从工作线程调用操作“main”方法(在这里放置一个断点,你会看到它不在主线程上).
>您的应用程序变得繁荣,因为您已经从与其创建的线程不同的线程访问了受管对象上下文.
解:
在操作的main方法中初始化托管对象上下文.