Kris
Kris

Reputation: 155

iOS CoreData parsing from CSV cannot save error 1570 nil object

I'm quite new to objective c and iOS, would really appreciate some help here. I have been banging my head against the wall trying to get this working, but keep getting the error:

Failed to save to data store: The operation couldn’t be completed. (Cocoa error 1570.)

What I am doing is importing a CSV file.

From what I can tell it is partially working. CSV is correctly being parsed, I'm getting all the correct values, and I have debugged through and from what I can tell the KA objects are all getting the right values.

But there seems to be something wrong with how I am doing the relationships - the 1570 issue is coming from a nil newTrainingDay's required date field (which seems like it is filled from when I've debugged). I have a feeling something else is wrong but I am not sure what..

Can anyone tell me what I am doing wrong here?

Upvotes: 0

Views: 129

Answers (1)

pbasdf
pbasdf

Reputation: 21536

I think the problem stems from creating and inserting new objects into the database, before then searching to see if there is an existing object that meets your needs. Take this code, for example:

 // look for existing day
    KATrainingDay *newTrainingDay = [NSEntityDescription insertNewObjectForEntityForName:@"KATrainingDay" inManagedObjectContext:self.managedObjectContext];
    // Fetching
    fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"KATrainingDay"];
    [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"date == %@", date]];
    // Execute Fetch Request
    fetchError = nil;
    NSArray *trainingDays = [self.managedObjectContext executeFetchRequest:fetchRequest error:&fetchError];
    // if you found it
    if (!fetchError) {
        if ([trainingDays count]) {
            for (KATrainingDay *day in trainingDays) {
                newTrainingDay = day;
            }
        } else {
            // set name and date for training day
            newTrainingDay.date = date;
            newTrainingDay.name = trainingDayNameString;
            [newTrainingDay addRoutinesObject:newTrainingRoutine];
            [newTrainingRoutine addTrainingDaysObject:newTrainingDay];
        }

You start by creating and inserting a KATrainingDay into your context, and then do a fetch to look for a KATrainingDay with the right date. If you find it, you assign your pointer (newTrainingDay) to the object you just fetched. But the object you just inserted is still in the context (though you no longer have a pointer to it) and will have nil values for all its attributes and relationships. Hence when you save, that object fails the required day constraint.

To fix this, insert new objects only if you don't find a match with your fetch:

 // look for existing day
    KATrainingDay *newTrainingDay;
    // Fetching
    fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"KATrainingDay"];
    [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"date == %@", date]];
    // Execute Fetch Request
    fetchError = nil;
    NSArray *trainingDays = [self.managedObjectContext executeFetchRequest:fetchRequest error:&fetchError];
    // if you found it
    if (!fetchError) {
        if ([trainingDays count]) {
            for (KATrainingDay *day in trainingDays) {
                newTrainingDay = day;
            }
        } else {
            // set name and date for training day
            newTrainingDay = [NSEntityDescription insertNewObjectForEntityForName:@"KATrainingDay" inManagedObjectContext:self.managedObjectContext]
            newTrainingDay.date = date;
            newTrainingDay.name = trainingDayNameString;
        } 
        [newTrainingDay addRoutinesObject:newTrainingRoutine];

(and likewise for the other entities). In the above I have also moved the addRoutinesObject: call outside that else block, so it will execute whether you find existing or create new (which I assume you want). And note you don't need to set both sides of the relationship - if you set one side, CoreData does the other for you automatically (assuming they are defined as inverses). One other tip, you don't need your for loop to get the last item in an array, you can just use:

newTrainingDay = [trainingDays lastObject];

Upvotes: 1

Related Questions