Search code examples
objective-ccore-datacore-data-migration

I insert my CoreData in background Context and when I fetch, it doesn't show the data


I am trying to do my Core-data operation on background context. I insert all my data on the background context but when I fetch on main thread, it doesnt show any data which I already inserted. I dont know, where am I doing the mistake...:( Any help appreciate.

This Is what I have tried for insert and the second one is for fetch the data.

- (void)insertNameAndSurnameInDataBase:(NSString *)name surname:(NSString *)surname numbers:(NSArray *)numbers labels:(NSArray *)labels {
    AppDelegate *appDel=(AppDelegate *)[UIApplication sharedApplication].delegate;

    NSManagedObjectContext *saveObjectContext = [appDel saveManagedObjectContext];
    NSManagedObjectContext *bgContext = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType];

    bgContext.parentContext = saveObjectContext;

    [bgContext performBlockAndWait:^{
        NSError *error;
        NameAndSurname *nameAndSurname = [NSEntityDescription insertNewObjectForEntityForName:@"NameAndSurname" inManagedObjectContext:bgContext];
        NSString *nSurname = [NSString stringWithFormat:@"%@ %@",name,surname];

        if (nSurname.length == 0) {
            nameAndSurname.nameSurname = [numbers objectAtIndex:0];
        } else {
            nameAndSurname.nameSurname = nSurname;
        }

        if ([bgContext save:&error]) {
        } else {
        }

        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"NameAndSurname" inManagedObjectContext:bgContext];

        // predicate
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"nameSurname =[c] %@", nSurname];

        [fetchRequest setEntity:entity];
        [fetchRequest setPredicate:predicate];
        [fetchRequest setReturnsObjectsAsFaults:NO];

        NSArray *fetchedObjects = [bgContext executeFetchRequest:fetchRequest error:&error];
        if([fetchedObjects count] > 0){
            [numbers enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
                id obj2 = [labels objectAtIndex:idx];
                obj = [obj stringByReplacingOccurrencesOfString:@" " withString:@""];

                ContactNumber *phoneNumber = [NSEntityDescription insertNewObjectForEntityForName:@"ContactNumber" inManagedObjectContext:bgContext];
                phoneNumber.number = obj;
                phoneNumber.label = obj2;
                phoneNumber.nameAndSurname = fetchedObjects[0];
                NSError *error;
                if ([bgContext save:&error]) {
                } else {
                }
            }];
        }
    }];
}



- (NSArray *)fetchNameAndSurname {
    AppDelegate *appDel = (AppDelegate *)[UIApplication sharedApplication].delegate;
    _managedObjectContext = [appDel managedObjectContext];

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"NameAndSurname"
                                              inManagedObjectContext:_managedObjectContext];

    [fetchRequest setSortDescriptors:@[[[NSSortDescriptor alloc] initWithKey:@"nameSurname" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)]]];
    [fetchRequest setEntity:entity];
    [fetchRequest setReturnsObjectsAsFaults:NO];

    NSError *error = nil;
    NSArray *fetchedObjects = [_managedObjectContext executeFetchRequest:fetchRequest error:&error];

    return [fetchedObjects valueForKey:@"nameSurname"];
}



Solution

  • The mistake you are making is to not test the many little pieces of this code which could be not working as expected. To troubleshoot something like this, you must start at the beginning and test one piece at a time. The first issue I see is confusion between managed object contexts…

    • It appears that the method saveManagedObjectContext is a getter for your main managed object context. In English, save is a verb, so that this method name implies that it is saving some managed object context. If I am correct, you should change the name saveManagedObjectContext to maybe mainMangaedObjectContext.

    • The statement _managedObjectContext = [appDel managedObjectContext] is quite nonstandard, assigning to an instance variable from what appears to be its getter. If, as usual, _managedObjectContext is the instance variable backing the property managedObjectContext, this statement has no effect.

    • In your first method you use [appDel saveManagedObjectContext], and in your second method you use [appDel managedObjectContext]. It looks like these should be the same context in order for your fetch to work. Are they?

    UPDATE:

    As you stated in your comment, that fixes the saving, but now you have a performance problem – saving to the persistent store on disk blocks the user interface, which is what your original code was trying to fix.

    This is a solved problem. The solution is that your main-thread context, which interfaces the user, should be a child of your background-thread context which interfaces to the persistent store. It is explained nicely with code in this 2015 blog post by Marcus Zarra. For further reading, Chad Wilken has published a slight variation. Both are written in Objective-C for you :)