如何在使用 UISearchDisplayController 的同时正确删除 UITableView 中的行(由 NSFetchedResultsController 控制)?

发布于 2024-09-30 21:32:33 字数 2959 浏览 4 评论 0原文

在我的 iPhone 应用程序中,我有一个(未分组的)UITableView,它使用所有“花哨功能”,包括 (a) NSFetchedResultsController 来保持更新,(b) 多个部分,(c) 添加和删除项目的能力,以及 (d) UISearchDisplayController 允许用户搜索列表,该列表可能会很长。

当用户在搜索过程中尝试删除项目时,我遇到了问题。我收到此错误:严重的应用程序错误。在调用 -controllerDidChangeContent: 期间,从 NSFetchedResultsController 的委托捕获了异常。无效更新:节数无效。更新后表视图中包含的节数 (1) 必须等于更新前表视图中包含的节数 (21),加上或减去插入或删除的节数(0 个插入,0 个已删除)。与 userInfo (null)

似乎问题是由于以下事实引起的:当应用程序切换到搜索模式时,它会切换到单个部分(“而不是通常的部分数量(按字母顺序排列,AZ)”)搜索结果”)。因此,当它尝试删除该项目时,它会认为正确的部分数量是当它只是在单个部分(搜索结果)中时较大的数字。

这是我用于管理获取结果控制器的代码。 您知道处理此类操作的正确方法是什么吗?

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
// if (!self.searchDisplayController.isActive) {
  [self.tableView beginUpdates];
// }
}


- (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)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:
   if (!self.searchDisplayController.isActive) {
    [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
   } else {
   // I currently don't do anything if the search display controller is active, because it is throwing similar errors.
   }
   break;

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
// if (!self.searchDisplayController.isActive) {
  [self.tableView endUpdates];
// }
}

In my iPhone app, I have a (non-grouped) UITableView which uses all the "bells and whistles," including (a) NSFetchedResultsController to keep it updated, (b) multiple sections, (c) the ability to add and delete items, and (d) the UISearchDisplayController to allow the user to search through the list, which can get to be very long.

I am running into issues when the user tries to delete items while they are in the process of searching. I am getting this error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. Invalid update: invalid number of sections. The number of sections contained in the table view after the update (1) must be equal to the number of sections contained in the table view before the update (21), plus or minus the number of sections inserted or deleted (0 inserted, 0 deleted). with userInfo (null)

It seems that the problem arises from the fact that when the app switches to search mode, instead of the usual number of sections (which are alphabetical, A-Z), it switches to a single section ("Search Results"). So, when it tries to delete the item, it is thinking that the proper number of sections is the larger number when it is simply in a single section (Search Results).

Here's my code for managing the fetched results controller. Do you know what is the proper way to handle this type of action?

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
// if (!self.searchDisplayController.isActive) {
  [self.tableView beginUpdates];
// }
}


- (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)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:
   if (!self.searchDisplayController.isActive) {
    [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
   } else {
   // I currently don't do anything if the search display controller is active, because it is throwing similar errors.
   }
   break;

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
// if (!self.searchDisplayController.isActive) {
  [self.tableView endUpdates];
// }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

巴黎夜雨 2024-10-07 21:32:33

如果您有一个 NSFetchedResultsController,为什么不创建一个谓词并将其设置在控制器上作为过滤器呢?

像这样的东西:

NSPredicate *predicate =[NSPredicate predicateWithFormat:@"name contains[cd] %@", searchText];
[fetchedResultsController.fetchRequest setPredicate:predicate];

NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
        // Handle error
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        // Fail
}           

[self.tableView reloadData];

If you have an NSFetchedResultsController, why don't you just create a predicate and set it on the controller as a filter?

Something like this:

NSPredicate *predicate =[NSPredicate predicateWithFormat:@"name contains[cd] %@", searchText];
[fetchedResultsController.fetchRequest setPredicate:predicate];

NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
        // Handle error
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        // Fail
}           

[self.tableView reloadData];
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文