NSFetchedResultsController: использование NSManagedObjectContext во время обновления приводит к сбою - PullRequest
1 голос
/ 29 мая 2010

Вот интерфейс моего контроллера класса:

@interface ProjectListViewController : UITableViewController <NSFetchedResultsControllerDelegate> {
    NSFetchedResultsController *fetchedResultsController;
    NSManagedObjectContext *managedObjectContext;
}

@end

Я использую следующий код для инициализации fetchedResultsController :

if (fetchedResultsController != nil) {
    return fetchedResultsController;
}

    // Create and configure a fetch request with the Project entity.
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Project" inManagedObjectContext:managedObjectContext];
    [fetchRequest setEntity:entity];

    // Create the sort descriptors array.
    NSSortDescriptor *projectIdDescriptor = [[NSSortDescriptor alloc] initWithKey:@"projectId" ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:projectIdDescriptor, nil];
    [fetchRequest setSortDescriptors:sortDescriptors];

    // Create and initialize the fetch results controller.
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest 
                                                                                            managedObjectContext:managedObjectContext 
                                                                                              sectionNameKeyPath:nil 
                                                                                                       cacheName:nil];
    self.fetchedResultsController = aFetchedResultsController;
    fetchedResultsController.delegate = self;

Как видите, я использую тот же managedObjectContext , как определено в классе моего контроллера

Вот принятие протокола NSFetchedResultsControllerDelegate:

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    // The fetch controller is about to start sending change notifications, so prepare the table view for updates.
        [self.tableView beginUpdates];
}


- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
        UITableView *tableView = self.tableView;

        switch(type) {

            case NSFetchedResultsChangeInsert:
                [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
                break;

            case NSFetchedResultsChangeDelete:
                [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
                break;

            case NSFetchedResultsChangeUpdate:
                [self _configureCell:(TDBadgedCell *)[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
                break;

            case NSFetchedResultsChangeMove:
                if (newIndexPath != nil) {
                    [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
                    [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
                }
                else {
                    [tableView reloadSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade];
                }
            break;
        }
}


- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
        switch(type) {

            case NSFetchedResultsChangeInsert:
                [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
                break;

            case NSFetchedResultsChangeDelete:
                [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
                break;
        }
}


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
        [self.tableView endUpdates];
}

Внутри _configureCell: atIndexPath: метод У меня есть следующий код:

    NSFetchRequest *issuesNumberRequest = [NSFetchRequest new];
    NSEntityDescription *issueEntity = [NSEntityDescription entityForName:@"Issue" inManagedObjectContext:managedObjectContext];
    [issuesNumberRequest setEntity:issueEntity];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"projectId == %@", project.projectId];
    [issuesNumberRequest setPredicate:predicate];
    NSUInteger issuesNumber = [managedObjectContext countForFetchRequest:issuesNumberRequest error:nil];
    [issuesNumberRequest release];

Я снова использую managedObjectContext.

Но когда я пытаюсь вставить новый проект, приложение вылетает со следующим исключением:

Ошибка подтверждения в - [UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-984.38/UITableView.m:774 Завершение приложения из-за необученного исключение 'NSInternalInconsistencyException', причина: «Неверное обновление: недействительно количество строк в разделе 0. количество строк, содержащихся в существующий раздел после обновления (4) должно быть равно количеству строк содержится в этом разделе до обновление (4), плюс или минус число из строк, вставленных или удаленных из этого раздел (1 вставлено, 0 удалено).

К счастью, я нашел обходной путь: если я создам и использую отдельный NSManagedObjectContext внутри _configureCell: atIndexPath: метод приложение не будет аварийно завершено!

Я только хочу знать, правильно ли это поведение или нет?

Вот пример проекта. Обратите внимание на методы _configureCell: atIndexPath: и _addSomeRows в CrashMeViewController

1 Ответ

0 голосов
/ 22 июня 2010

Исправлено в iOS 4.0

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...