Core data Child context failing to update Main context

人盡茶涼 提交于 2019-12-25 12:40:14

问题


Further down the rabbit hole I go. I've got my child moc saving successfully now: Core Data Parent/Child context save fail

My next hurdle is that my Main context is failing to update with the child results. Basically my tableview that had 200 entries is now blank.

Here is my setup: (contains all of the code from previous post)

In my app delegate I setup the main managedobjectcontext with the NSMainQueueConcurrencyType:

- (NSManagedObjectContext *)managedObjectContext
{
    if (_managedObjectContext != nil) {
        return _managedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {

        _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];//[[NSManagedObjectContext alloc] init];
        //_managedObjectContext = [[NSManagedObjectContext alloc] init];
        [_managedObjectContext setPersistentStoreCoordinator:coordinator];
    }
    return _managedObjectContext;
}

When my data call returns the json I setup the child moc and do the work like this:

- (void)APIManager:(APIManager *)manager didGetContactsWithInfo:(NSDictionary *)info
{

    NSManagedObjectContext *mainMOC = self.managedObjectContext;
    NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

    [moc setParentContext:mainMOC];
    [moc setUndoManager:nil];

BCRAccount *account2 = (BCRAccount*)[moc objectWithID:[self.loggedInAccount objectID]];

     [moc performBlock:^{
        //do all work on child moc
        //within block there is a core data relationship reference:


[contact addAccountsObject:account2];

            [self saveMOC:moc completion:^(NSError *error) {
                // Completion handler is called from main-thread, after save has finished
                if (error) {
                    // Handle error
                    NSLog(@"save error %@", error);
                } else {
                    NSLog(@"save success");

                }
            }];

}];

The saveMOC method:

- (void)saveMOC:(NSManagedObjectContext*)moc
     completion:(void(^)(NSError *error))completion {
    [moc performBlock:^{
        NSError *error = nil;
        if ([moc save:&error]) {
            if (moc.parentContext) {
                return [self saveMOC:moc.parentContext completion:completion];
            }
        }
        if (completion) {
            dispatch_async(dispatch_get_main_queue(), ^{
                completion(error);
        }
    }];
}

Ok, this was saving until I re-enabled the relationship between a "Account" entity and the "Contact" entity.

The Account entity has a relationship "contacts" with a destination of "Contact" and the inverse is "accounts". The delete rule is "Nullify" and the type is "To many".

The Contact entity has a relationship "accounts" with a destination of "Account" with inverse set to "contacts". The delete rule is "Nullify" and the type is "To many".

The moc error as a result of this relationship is:

Error Domain=NSCocoaErrorDomain Code=1550 "contacts is not valid." UserInfo={Dangling reference to an invalid object.=null, NSValidationErrorValue=Relationship 'contacts' on managed object

I think this error is the source of the issue, but for context the following is the NSFetchedResultsController used in the view controller that displays the tableview of contacts:

- (NSFetchedResultsController *)fetchedResultsController
{
    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:[BCRContact entityName] inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];

    // Set the batch size to a suitable number.
    [fetchRequest setFetchBatchSize:20];

    // Edit the sort key as appropriate.

   NSArray *sortDescriptors =
    @[[NSSortDescriptor sortDescriptorWithKey:@"isNewContact" ascending:NO],
      [NSSortDescriptor sortDescriptorWithKey:@"status" ascending:YES],
      [NSSortDescriptor sortDescriptorWithKey:@"fullName" ascending:YES],
      [NSSortDescriptor sortDescriptorWithKey:@"company" ascending:YES]];

    [fetchRequest setSortDescriptors:sortDescriptors];

    fetchRequest.predicate = [self predicateWithSearchString:nil];

    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
    aFetchedResultsController.delegate = self;
    self.fetchedResultsController = aFetchedResultsController;

    NSError *error = nil;
    if (![self.fetchedResultsController performFetch:&error]) {
        // Replace this implementation with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        //NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    return _fetchedResultsController;
}

The table generates the cells here:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

    static NSString *CellIdentifier = @"Cell";

    ContactListCell *cell = (ContactListCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[ContactListCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
        cell.selectionStyle = UITableViewCellSelectionStyleGray;
    }

    [self configureCell:cell atIndexPath:indexPath];
    return cell;
 }

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
    BCRContact *contact = [self.fetchedResultsController objectAtIndexPath:indexPath];
    //update cell
 }

Ok, That is the rough setup. The tableview would populate fine when it was just one context. So, the question is how to get the child moc data reflected properly in the tableview.

Let me know if I can provide any more details.

|improve this question

回答1:


cracked it! before the performBlock i needed to establish the account entity via the moc with objectWithID. BCRAccount account2 = (BCRAccount)[moc objectWithID:[self.loggedInAccount objectID]]; after that the relationship worked: [contact addAccountsObject:account2];



来源:https://stackoverflow.com/questions/33620220/core-data-child-context-failing-to-update-main-context

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!