UISearchController NSFetchResultsController

时间:2015-04-08 06:32:18

标签: ios uitableview ios8 uisearchcontroller

我收到此错误:

  

CoreData:错误:严重的应用程序错误。抓住了一个例外   在调用期间来自NSFetchedResultsController的委托   -controllerDidChangeContent :.尝试删除第0部分中的第5行,该部分在使用userInfo(null)更新之前仅包含1行。如果我   编辑第一个或第二个而不是最后一切都在工作。

我有一个tableview和UISearchController,当我触摸tableview中的行时,它会发送给我另一个vc,我可以编辑我的日记。 一切都工作得很好,除非我搜索一些东西,如果结果是我的TableView的最后一个条目,当我尝试编辑并保存它时,给我上面写的错误。

@implementation PlumbListTableViewController


-(void)viewDidLoad {
    [super viewDidLoad];
  [self.fetchedResultsController performFetch:nil];
 }

-(void) viewWillAppear:(BOOL)animated {
    [super viewWillAppear:YES];

   self.searchController =[[UISearchController alloc] initWithSearchResultsController:nil];

    self.searchController.searchResultsUpdater = self;
    self.searchController.dimsBackgroundDuringPresentation = NO;
    self.searchController.searchBar.frame = CGRectMake(self.searchController.searchBar.frame.origin.x, self.searchController.searchBar.frame.origin.y, self.searchController.searchBar.frame.size.width, 44.0);

    self.tableView.tableHeaderView = self.searchController.searchBar;
   self.searchController.searchBar.delegate = self;

     self.tabBarController.tabBar.hidden = NO;
    [self showTotalSum];
    [self.tableView reloadData];

}

-(void)searchBarCancelButtonClicked:(UISearchBar *)searchBar{
[self.tableView reloadData];
}

- (void)searchForText:(NSString *)searchText
{
    CoreDataStack *coreDataStack = [CoreDataStack defaultStack];
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"AddEntry"];
    fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"date" ascending:NO]];
    if (self.searchController.searchBar.text.length == 0) {
         NSError *error = nil;
        self.filteredList = [coreDataStack.managedObjectContext executeFetchRequest:fetchRequest error:&error];
    } else {

    if (coreDataStack.managedObjectContext) {

   NSPredicate *predicate = [NSPredicate predicateWithFormat:@"titluPlumb contains[c] %@", searchText];
        [fetchRequest setPredicate:predicate];
          NSError *error = nil;
        self.filteredList = [coreDataStack.managedObjectContext executeFetchRequest:fetchRequest error:&error];
    }
    }
}



- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
    NSString *searchString = searchController.searchBar.text;

    [self searchForText:searchString ];
    [self.tableView reloadData];

}

-(void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope
{
    [self updateSearchResultsForSearchController:self.searchController];
}

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {


    if ([segue.identifier isEqualToString:@"edit"]) {
        UITableViewCell *cell = sender;
        NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
        UINavigationController *navigationController = segue.destinationViewController;
        PlumbAddViewController *entryViewController = (PlumbAddViewController *)navigationController.topViewController;

        if (self.searchController.active) {
            entryViewController.entry = [self.filteredList objectAtIndex:indexPath.row];
        } else {
        entryViewController.entry = [self.fetchedResultsController objectAtIndexPath:indexPath];
        }
   }
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    // Return the number of sections.

    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    // Return the number of rows in the section.

    if (self.searchController.active)
    {
           return [self.filteredList count];
      }
    else
    {
        id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section];
        return [sectionInfo numberOfObjects];
   }

}


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

    static NSString *CellIdentifier = @"Cell";
    ConfigureCellPlumb *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    AddEntry *entry = nil;

    if (self.searchController.active){

        entry = [self.filteredList objectAtIndex:indexPath.row];

    } else {

           entry = [self.fetchedResultsController objectAtIndexPath:indexPath];
    }

    cell.titluView.text = entry.titluPlumb;
    cell.descriereView.text = entry.bodyPlumb;

    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"MM/dd/yyyy"];
    NSDate *date = [NSDate dateWithTimeIntervalSince1970:entry.date];
    cell.dataLabel.text = [dateFormatter stringFromDate:date];

    if (entry.imageDataPlumb) {
        cell.imagineView.image = [UIImage imageWithData:entry.imageDataPlumb];
    } else {
        cell.imagineView.image = [UIImage imageNamed:@"icn_noimage"];
    }

    return cell;

}


- (NSFetchRequest *)entryListFetchRequest {
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"AddEntry"];

    fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"date" ascending:NO]];

    return fetchRequest;
}

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

    CoreDataStack *coreDataStack = [CoreDataStack defaultStack];
    NSFetchRequest *fetchRequest = [self entryListFetchRequest];

    _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:coreDataStack.managedObjectContext sectionNameKeyPath:@"sectionName" cacheName:nil];
    _fetchedResultsController.delegate = self;

    return _fetchedResultsController;
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    AddEntry *entry = [self.fetchedResultsController objectAtIndexPath:indexPath];

    CoreDataStack *coreDataStack = [CoreDataStack defaultStack];
    [[coreDataStack managedObjectContext] deleteObject:entry];
    [coreDataStack saveContext];
}



- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {

    [self.tableView beginUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {

    switch (type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;
        case NSFetchedResultsChangeDelete:
            [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;
        case NSFetchedResultsChangeUpdate:
            [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;
        case NSFetchedResultsChangeMove:
            [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            [self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            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:UITableViewRowAnimationAutomatic];
            break;
        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;
        case NSFetchedResultsChangeUpdate:
            [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;
        }

}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {

    [self.tableView endUpdates];

}

@end

更新:

- (NSFetchRequest *)entryListFetchRequest {
    self.searchFetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"AddEntry"];

    self.searchFetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"date" ascending:NO]];





    return self.searchFetchRequest;
}


- (NSFetchedResultsController *)fetchedResultsController {
    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }
    self.coreDataStack = [CoreDataStack defaultStack];
    NSFetchRequest *fetchRequest = [self entryListFetchRequest];
    _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.coreDataStack.managedObjectContext sectionNameKeyPath:@"sectionName" cacheName:nil];
    _fetchedResultsController.delegate = self;

    if (self.searchController.searchBar.text.length != 0) {
        NSString *searchText = self.searchController.searchBar.text;
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"titluPlumb contains[c] %@", searchText];
        [self.searchFetchRequest setPredicate:predicate];

             NSError *error = nil;
        self.filteredList = [self.coreDataStack.managedObjectContext executeFetchRequest:self.searchFetchRequest error:&error];
    }


return _fetchedResultsController;
}

更新2

- (NSFetchedResultsController *)fetchedResultsController {
    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }
    self.coreDataStack = [CoreDataStack defaultStack];
    NSFetchRequest *fetchRequest = [self entryListFetchRequest];

    if (self.searchController.searchBar.text.length !=0) {
       NSString *searchText = self.searchController.searchBar.text;
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"titluPlumb contains[c] %@", searchText];
        fetchRequest.predicate = predicate;
    }

    _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.coreDataStack.managedObjectContext sectionNameKeyPath:@"sectionName" cacheName:nil];
    _fetchedResultsController.delegate = self;

    return _fetchedResultsController;
}


- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{

self.fetchedResultsController = nil;             [self.tableView reloadData];

    }
}

更新3

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    // Return the number of sections.

    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    // Return the number of rows in the section.

        id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section];
        return [sectionInfo numberOfObjects];


}


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

    static NSString *CellIdentifier = @"Cell";
    ConfigureCellPlumb *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    AddEntry *entry = nil;

           entry = [self.fetchedResultsController objectAtIndexPath:indexPath];


    cell.titluView.text = entry.titluPlumb;
    cell.descriereView.text = entry.bodyPlumb;

    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"MM/dd/yyyy"];
    NSDate *date = [NSDate dateWithTimeIntervalSince1970:entry.date];
    cell.dataLabel.text = [dateFormatter stringFromDate:date];

    if (entry.imageDataPlumb) {
        cell.imagineView.image = [UIImage imageWithData:entry.imageDataPlumb];
    } else {
        cell.imagineView.image = [UIImage imageNamed:@"icn_noimage"];
    }

    return cell;

}

更新4

- (NSFetchedResultsController *)fetchedResultsController {
    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }
    self.coreDataStack = [CoreDataStack defaultStack];
   self.searchFetchRequest = [self entryListFetchRequest];

    if (self.searchController.searchBar.text.length !=0) {
       NSString *searchText = self.searchController.searchBar.text;
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"titluPlumb contains[c] %@", searchText];
        self.searchFetchRequest.predicate = predicate;
        [self.tableView reloadData];

    }

    _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:self.searchFetchRequest managedObjectContext:self.coreDataStack.managedObjectContext sectionNameKeyPath:@"sectionName" cacheName:nil];
    _fetchedResultsController.delegate = self;


    return [_fetchedResultsController fetchedObjects];
}


- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
 self.fetchedResultsController = nil;
    [self.tableView reloadData];


     NSLog(@"%@", self.searchFetchRequest.predicate);
}

1 个答案:

答案 0 :(得分:1)

问题是你的桌面视图同时由2个源驱动(在这种情况下),因为你在搜索时没有完全关闭FRC。因此,您进行搜索并进行编辑,FRC会看到并尝试更新表格,但是 - 表格当前没有显示FRC行 - 所以有时它会失败。

使用FRC通过更改获取请求中的谓词来执行搜索,或者在您进行搜索时销毁FRC并在完成后重新创建它。


因此,将您的FRC方法更改为:

- (NSFetchedResultsController *)fetchedResultsController {
    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }
    self.coreDataStack = [CoreDataStack defaultStack];
    NSFetchRequest *fetchRequest = [self entryListFetchRequest];

    if (self.searchController.searchBar.text.length != 0) {
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"titluPlumb contains[c] %@", searchText];
        fetchRequest.predicate = predicate;
    }

    _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.coreDataStack.managedObjectContext sectionNameKeyPath:@"sectionName" cacheName:nil];
    _fetchedResultsController.delegate = self;

    return _fetchedResultsController;
}

每当您开始搜索/更改搜索文本/结束搜索时,请执行以下操作:

self.fetchedResultsController = nil;
[self.tableView reloadData];