Search code examples
ioscore-datansmanagedobjectcontext

Saving the managedObjectContext for a specific object


I'm trying to learn Core Data, and am having trouble updating the MOC after adding new objects to an existing object. I can create the original object, a training day, and I can add exercise objects to that training day, but I can't figure out how to save the context so that later in my application I can find all exercises in a training day.

Any ideas??

Here is my code:

// Data from JSON
NSArray *trainingDayData = responseData[@"training_days"];
for (NSDictionary *aTrainingDay in trainingDayData) {

    // Find the specific training day and save the MOC, creating the trainingDayObject
    NSNumber *idTrainingDay = [NSNumber numberWithInt:[[aTrainingDay objectForKey:kID_KEY] intValue]];
    VitTrainingDay *trainingDayObject = [VitTrainingDay trainingDayCreateOrObjectWithID:idTrainingDay];

     // Configure the VitTrainingDay object's fields
     trainingDayObject.name = aTrainingDay[@"name"];
     trainingDayObject.order = aTrainingDay[@"order"];              

}
// assign exercises to each trainingDayObject(this is inside a larger for loop)
trainingDayObject.userExercise = [NSSet setWithArray:userExerciseObjects];

// Below are attempt one and two to update the MOC after assigning exercises to the trainingDayObject.

// This works to save the updated MOC, but also adds two blank trainingDayObjects, since it 'insertNewObjectForEntityName', which I don't want. 
trainingDayObject = [NSEntityDescription insertNewObjectForEntityForName:@"TrainingDay" inManagedObjectContext:self.context];

//This as far as I can tell is doing nothing. It just points to the conventional MOC save method. I pull it out below.
[self.coreDataManager saveContextForManagedObjectContext:self.context];

Here is the saveContextForManagedObjectContext method I call above:

- (void)saveContextForManagedObjectContext:(NSManagedObjectContext *)moc
{
    NSError *error = nil;
    if (![moc save:&error]) {
        NSLog(@"Can't Save! %@ %@", error, [error localizedDescription]);
    }
}

Solution

  • I am a bit confused about your loops but assuming the first one is used to get each Training Day, sets some values and then get the Exercises for that day and set the relationships try the following.

    Note that this line of code below is what creates the NSManagedObject, so you need to call it to create each TrainingDay object and each Exercise object.

    trainingDayObject = [NSEntityDescription insertNewObjectForEntityForName:@"TrainingDay" inManagedObjectContext:self.context];
    

    Not sure what this line does but presumably it creates a new object or returns one if it already exists

    VitTrainingDay *trainingDayObject = [VitTrainingDay trainingDayCreateOrObjectWithID:idTrainingDay];
    

    Unless it is also calling insertNewObjectForEntityForName then it should be replaced with a call that does create the NSManagedObject or searches and returns one with a matching ID. If it is calling insertNewObjectForEntityForName then you should remove the line below because that just creates another trainingDay object in the database without setting any attribute values.

    Try something like this

        // Data from JSON
        NSArray *trainingDayData = responseData[@"training_days"];
    
        for (NSDictionary *aTrainingDay in trainingDayData) {
    
            // Find the specific training day ID
            NSNumber *idTrainingDay = [NSNumber numberWithInt:[[aTrainingDay objectForKey:kID_KEY] intValue]];
    
             //Create the Core Data Object
             //Assume VitTrainingDay is a NSManagedObject subclass
             VitTrainingDay *trainingDayObject = [NSEntityDescription insertNewObjectForEntityForName:@"TrainingDay" inManagedObjectContext:self.context];
    
             // Set the attributes
             trainingDayObject.ID = idTrainingDay;
             trainingDayObject.name = aTrainingDay[@"name"];
             trainingDayObject.order = aTrainingDay[@"order"];              
    
    
           // assign exercises to each trainingDayObject
           for (SomeSourceObject *object in SomeExercisesSource) {
               ExerciseObject *exercise = [NSEntityDescription insertNewObjectForEntityForName:@"ExerciseObject" inManagedObjectContext:self.context];
    
               // Set the exercises parent object (training day)
               exercise.trainingDay = trainingDayObject;
               exercise.details = object.details;
    
           }
    
        }
    
    
    NSError *error = nil;
    if (![self.context save:&error]) {
        NSLog(@"Can't Save! %@ %@", error, [error localizedDescription]);
    } else {
        NSLog(@"Save successful");
    }
    

    My guess is you need to search for an existing TrainingDay object with the same ID before creating a new one so if that is what this call [VitTrainingDay trainingDayCreateOrObjectWithID:idTrainingDay]; does then use it instead.