代码之家  ›  专栏  ›  技术社区  ›  Kentzo

nsFetchedResultsController:在更新期间使用nsManagedObjectContext会导致崩溃

  •  1
  • Kentzo  · 技术社区  · 15 年前

    以下是我的控制器类的接口:

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

    我用以下代码初始化 提取结果控制器 :

    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;
    

    如你所见,我也在用 管理对象上下文 在我的控制器类中定义

    以下采用了控制删除协议中的nsfetchedresults:

    - (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 由于未捕获而终止应用程序 例外 'nsInternalConsistenceyException', 原因:'无效更新:无效 第0节中的行数。这个 中包含的行数 更新后的现有部分(4) 必须等于行数 包含在该节之前 更新(4),加上或减去数字 从中插入或删除的行数 节(插入1,删除0)。'

    幸运的是,我找到了一个解决方法:如果我在_configureCell:atindexpath:method app中创建和使用单独的nsmanagedObjectContext,那么它不会崩溃!

    我只想知道,这种行为是否正确?

    Here is a sample project. 注意crashmeViewController的“_configureCell:atindexpath:”和“_addsomerows”方法

    1 回复  |  直到 15 年前
        1
  •  0
  •   Kentzo    15 年前

    已在iOS 4.0中修复