Multithreading – why does my application crash when modifying the core data relationship in the nsoperation subclass?

background

I have the following object trees:

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...

>Users can assign a group to an item All descendants are set to this item. > This locks the main thread, so I use nsoperations. > I am using this method approved by apple to see the nsmanagedobjectcontextdidsavenotification and merge it into the main context

problem

My save has failed with the following error:

Pending changes cannot be processed before saving After 100 attempts, the context is still dirty Usually this recursive dirty is caused by a bad validation method, - willsave or notification handler

I tried

I've eliminated all the complexity of my application and done the simplest project I can think of And the error still occurs I tried:

>Set the maximum number of operands on the queue to 1 or 10. > Call refreshobject: mergechanges: at several points in the nsoperation subclass. > Set the merge policy in the managed object context. > Establish and analyze It's empty

My question

How do I set up relationships in nsoperation without my application crashing? Of course, isn't this the limitation of core data? Can it?

code

Download my project: http://synapticmishap.co.uk/CDMTTest1.zip

main controller

@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

Perform relationship operations

@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

data model

Update 1

I've tried some, and even without merging, I still throw an exception After modifying the relationship, it is sufficient to save the management object context in another thread

I have a shared persistence store coordinator with application representatives I've tried to create a separate nspersistent storecoordinator for threads using the same URL as the data store, but core data complains

I am happy to offer advice on how to make thread coordinators The core data file mentions a method, but I can't see how

Solution

You are crossing a very bad stream (in this case, a thread) in coredata Look at this:

Starttest is called from a button (it is ibaction, assuming the button is clicked) on the main thread > your for loop uses the initialization program trainggroup to create a jgmakerelationship object: withproject: (this should be called init, and super may be called, but this will not cause this problem) > In the main thread, create a new managed object context in the operation. > Now the operation queue calls the operation "main" method from the worker thread (place a breakpoint here and you will see that it is not on the main thread). > Your application thrives because you have accessed the managed object context from a different thread than the thread it created

Solution:

Initializes the managed object context in the main method of the operation

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>