在 tableViewController 中使用重新加载的 CoreData

Posted

技术标签:

【中文标题】在 tableViewController 中使用重新加载的 CoreData【英文标题】:Work with reloaded CoreData in tableViewController 【发布时间】:2014-03-13 16:08:46 【问题描述】:

我在将数据保存到 CoreData 并在表格视图控制器上显示时遇到问题。问题在此视频中:https://www.youtube.com/watch?v=6Di9zeAeBWs&feature=youtu.be

当我删除类时不会出现任何问题。该课程已正确删除。(我的视频的第 1 部分)。但是当我添加一个新类时,程序报错:

2014-03-13 16:31:02.771 IISForTeachers[30568:70b] CoreData:错误:严重的应用程序错误。在调用 -controllerDidChangeContent: 期间,从 NSFetchedResultsController 的委托中捕获了一个异常。无效更新:第 0 节中的行数无效。更新后现有节中包含的行数 (3) 必须等于更新前该节中包含的行数 (3),加上或减去数字从该部分插入或删除的行数(0 插入,1 删除)加上或减去移入或移出该部分的行数(0 移入,0 移出)。与 userInfo (null) 2014-03-13 16:31:02.774 IISForTeachers[30568:70b] _context SAVED 对持久存储的更改。

错误后将日期保存到持久存储。数据的保存工作正常,因为我在表格视图控制器中看到了新的类,当我停止并再次运行应用程序时,新数据就在那里。但是当我添加一个新类而不是删除一个类时,应用程序崩溃(视频的第 2 部分)。

当我再次运行应用程序时,新类在表格视图中,我删除它没有问题(第 3 部分)。

这是我删除单元格的函数代码:

-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
    if(debug == 1)
        NSLog(@"Running %@ '%@'",self.class, NSStringFromSelector(_cmd));
    

    CoreDataHelper *cdh = [(AppDelegate *) [[UIApplication sharedApplication] delegate] cdh];

    if (editingStyle == UITableViewCellEditingStyleDelete) 

        SchoolClass *class = [self.frc objectAtIndexPath:indexPath];
        [[class managedObjectContext] deleteObject:class];
    

    [cdh saveContext];

    [self.tableView reloadData];

FRC

在 ClassesTVC.m 中获取日期(表视图控制器,在哪里显示所有类)。

-(void)configureFetch
    if(debug == 1)
        NSLog(@"Running %@ '%@'",self.class, NSStringFromSelector(_cmd));
    

    CoreDataHelper *cdh = [(AppDelegate *) [[UIApplication sharedApplication] delegate] cdh];

    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"SchoolClass"];

    request.sortDescriptors = [NSArray arrayWithObjects:[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES], nil];

    [request setFetchBatchSize:50];

    self.frc = [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                                   managedObjectContext:cdh.context
                                                     sectionNameKeyPath:nil
                                                              cacheName:nil];
    self.frc.delegate = self;


frc 在 CoreDataTVC.h(与表格视图控制器一起使用的通用类)中定义并定义为休闲:

@property (strong, nonatomic) NSFetchedResultsController *frc;

这里(CoreDataTVC)还有一个函数performFetch:

-(void)performFetch

    if(debug == 1)
        NSLog(@"Running %@ '%@'",self.class, NSStringFromSelector(_cmd));
    
    if(self.frc)
        [self.frc.managedObjectContext performBlock:^
            NSError *error = nil;
            if(![self.frc performFetch:&error])
                NSLog(@"Failed to perform fetch: %@", error);
            
            [self.tableView reloadData];
        ];
    
    else
        NSLog(@"Failed to fetch, the fetched results controller is nil.");
    

编辑-----------

我更改了我的代码,现在删除行的功能如下:

-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
    if(debug == 1)
        NSLog(@"Running %@ '%@'",self.class, NSStringFromSelector(_cmd));
    

    CoreDataHelper *cdh = [(AppDelegate *) [[UIApplication sharedApplication] delegate] cdh];

    if (editingStyle == UITableViewCellEditingStyleDelete) 
        [tableView beginUpdates];
        SchoolClass *class = [self.frc objectAtIndexPath:indexPath];
        [[class managedObjectContext] deleteObject:class];
        [tableView endUpdates];
    

    [cdh saveContext];

    [self.tableView reloadData];

现在应用程序运行良好,但仅当我插入一个输入(类名)时。当我插入班级名称并且班主任为空时,我可以删除有任何问题的单元格。但是,当我插入两个输入(班级名称、班级教师)时,应用程序再次显示错误。 这是对视频质量感到抱歉的应用程序行为:https://www.youtube.com/watch?v=PqSxqjuyZbU&feature=youtu.be

错误是一样的:

2014-03-14 12:15:08.309 IISForTeachers[35735:70b] CoreData:错误:严重的应用程序错误。在调用 -controllerDidChangeContent: 期间,从 NSFetchedResultsController 的委托中捕获了一个异常。无效更新:第 0 节中的行数无效。更新后现有节中包含的行数 (5) 必须等于更新前该节中包含的行数 (5),加上或减去数字从该部分插入或删除的行数(0 插入,1 删除)加上或减去移入或移出该部分的行数(0 移入,0 移出)。与 userInfo (null)

这是将 texfield 分配给对象类类型的代码。不知道哪里有问题。感谢您的帮助。

-(void)textFieldDidEndEditing:(UITextField *)textField
    if (debug == 1) 
        NSLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
    

    CoreDataHelper *cdh = [(AppDelegate *)[[UIApplication sharedApplication]delegate]cdh];

    SchoolClass *class = (SchoolClass*) [cdh.context existingObjectWithID:self.selectedClassID error:nil];

    if(textField == self.classNameTextField)
        if([self.classNameTextField.text isEqualToString:@""])
        
            self.classNameTextField.text = @"Nova trida";
        
        class.name = self.classNameTextField.text;
    
    else if (textField == self.classTeacherTextField)
        class.classTeacher = self.classTeacherTextField.text;
    

【问题讨论】:

你是如何实现你的 FRC 委托方法的? 删除commitForEditingStyle中的单元格而不是重新加载整个表格。[tableView deleteRows...等] 【参考方案1】:

在删除单元格时适当地更新您的视图,该错误会准确地告诉您 UITableView 的期望。

-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
    if(debug == 1)
        NSLog(@"Running %@ '%@'",self.class, NSStringFromSelector(_cmd));
    

    CoreDataHelper *cdh = [(AppDelegate *) [[UIApplication sharedApplication] delegate] cdh];

    if (editingStyle == UITableViewCellEditingStyleDelete) 
[tableView beginUpdates];
        SchoolClass *class = [self.frc objectAtIndexPath:indexPath];
        [[class managedObjectContext] deleteObject:class];

        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    [cdh saveContext];
        [tableView endUpdates];
    




【讨论】:

我正在尝试使用您的代码,但现在在添加新类后无法“简单”删除或删除。错误在此屏幕截图上:dropbox.com/s/jibpbs99isheij0/… 错误是说 UITableView 在执行删除后仍然包含 4 行。因此 ' 必须包含在该部分中插入或删除的行数的正数或负数(1 已删除)。预计会有 3 行。 嗯,但我不知道怎么做。我用新代码更新我的问题。感谢您的帮助。 我认为您需要在结束更新之前将上下文保存在 CoreData 中,否则该对象仍然存在。 如果您使用的是 NSFetchResultsController 为什么不使用委托方法来处理内容更改?

以上是关于在 tableViewController 中使用重新加载的 CoreData的主要内容,如果未能解决你的问题,请参考以下文章

拉动以刷新 tableviewcontroller 负载

tableViewController 中的 SideMenu

自定义 TableViewController 声音在 Swift 3 中播放和崩溃

在 Swift 3 中使用 didSelect 和 navigationController 在没有情节提要的情况下在 TableViewControllers 之间传递数据

在 TableViewController 的 pushViewController 方法中 navigationController = null (popover)

swift 4 中使用 performSegue 打开的关闭页面时,如何在视图控制器和 TableViewController 之间传递数据?