我有以下对象树:
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
并合并到主要背景中。
我的保存失败,出现以下错误:
Failed to process pending changes before save. The context is still dirty after 100 attempts. Typically this recursive dirtying is caused by a bad validation method, -willSave, or notification handler.
我已经剥离了我的应用程序的所有复杂性,并做了我能想到的最简单的项目。并且错误仍然存在。我试过了:
将队列上的最大操作数设置为1或10。
在NSOperation子类的多个点调用refreshObject:mergeChanges:
。
在托管对象上下文中设置合并策略。
构建和分析。它空了。
如何在没有我的应用程序崩溃的情况下在NSOperation中设置关系?当然这不能限制核心数据?可以吗?
下载我的项目: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
我已经尝试了一些,即使没有合并,仍会抛出异常。只需在修改关系后将托管对象上下文保存在另一个线程中就足够了。
我有一个与app delegate共享的持久性商店协调员。我已经尝试为与我的数据存储具有相同URL的线程创建一个单独的NSPersistentStoreCoordinator,但Core Data会抱怨。
我很乐意就如何为线程制作协调员提出建议。核心数据文档暗示有一种方法可以做到,但我看不出如何。
答案 0 :(得分:10)
你正在穿越这些在CoreData中非常糟糕的流(在这种情况下为线程)。以这种方式看待它:
解决方案:
在操作的main方法中初始化托管对象上下文。