Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Not found an object in coredata after added to a relationship

I have an issue with the fetch of an object after added in a relationship. The first time that i fetch the category, always found, then when i added to the relationship the following categories not found.

The relationship is a Many-To-Many.

Example:

  • Fetch category with categoryId = 10
  • Found category object
  • Added to the parent object relationship
  • Next object
  • If the several categories has the same id, categoryId = 10, not found

    NSManagedObjectContext *private = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    
       [private setParentContext:self.model.context];
        __block NSError *error = nil;
    
        [private performBlockAndWait:^{
    
            GPDeal *deal = [EKManagedObjectMapper objectFromExternalRepresentation:dic withMapping:[GPDeal objectMapping] inManagedObjectContext:private];
            for (NSDictionary *dic in responseObject[@"response"]) {
    
                GPCategory *category;
    
               //The first time always found
                if ((category = [GPCategory MR_findFirstByAttribute:@"catId" withValue:dic[@"mainAttribute"] inContext:private])) {
                    NSLog(@"Found");
                    [category addDealsObject:deal];
    
                } else {
                    NSLog(@"Not Found");
    
                }
    
            }
        }];
    
        NSError *PrivateError = nil;
        if (![private save:&PrivateError]) {
            NSLog(@"Unresolved error %@, %@", PrivateError, [PrivateError userInfo]);
            abort();
        }
    
        if (!error) {
            //Save on main moc
            [self.model saveWithErrorBlock:^(BOOL success, NSError *error) {
                if (!success) {
                    NSLog(@"Error saving context: %@\n%@", [error localizedDescription], [error userInfo]);
                }
            }];
    
        } else {
            NSLog(@"Error saving context: %@\n%@", [error localizedDescription], [error userInfo]);
        }
    

EDIT:

Solved , I guess my problem was that i forgot to save the main context in the end of each iteration .

        NSManagedObjectContext *backgroundMOC = [self.model backgroundMOC:self.model.context];

        [backgroundMOC performBlockAndWait:^{

            for (NSDictionary *dic in responseObject[@"response"]) {

                GPDeal *deal = [EKManagedObjectMapper objectFromExternalRepresentation:dic withMapping:[GPDeal objectMapping] inManagedObjectContext:backgroundMOC];

                GPCategory *category;
                if ((category = [GPCategory MR_findFirstByAttribute:@"catId" withValue:dic[@"mainAttribute"] inContext:backgroundMOC])) {
                    NSLog(@"Found with mainAttribute %@", dic[@"mainAttribute"]);
                    [deal addDealCategoryObject:category];
                }

                if([backgroundMOC hasChanges]) {
                    NSError * error;
                    [backgroundMOC save:&error];

                    [self.model.context performBlockAndWait:^{
                        if([self.model.context hasChanges]) {
                            NSError * error;
                            [self.model.context save:&error];
                        }
                    }];
                }
            }
        }];
like image 985
brunobasas Avatar asked Dec 27 '15 18:12

brunobasas


1 Answers

You may lack saving the MOC chain. For clarity, I have replaced the keyword private with the variable name backgroundMOC.

On the question above, I can only assume that the line NSManagedObjectContext *private = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; is technically similar to:

- (NSManagedObjectContext *)backgroundMOC:(NSManagedObjectContext *)mainMOC
{
    NSManagedObjectContext * threadManagedObjectContext = [[NSManagedObjectContext alloc]
                             initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    [threadManagedObjectContext setParentContext:mainMOC];
    [threadManagedObjectContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
    return threadManagedObjectContext;
}

passing self.model.context as mainMOC, with a self.model.context and a setMergePolicy.
Similarly, I must assume that self.model saveWithErrorBlock is technically identical to:

[mainMOC performBlockAndWait:^{
    if([mainMOC hasChanges]) {
        NSError * error;
        [mainMOC save:&error];
        // handle error
    }
}];

If so, the same should be said of the backgroundMOC (your private reference):

[backgroundMOC performBlockAndWait:^{
    if([backgroundMOC hasChanges]) {
        NSError * error;
        [backgroundMOC save:&error];
        // handle error
    }
}];

In other words, you want to ensure that your backgroundMOC and mainMOC save operation is executed from their respective threads, with performBlockAndWait.

like image 192
SwiftArchitect Avatar answered Sep 22 '22 01:09

SwiftArchitect