1

私はNSFetchedResultsControllerコアデータからいくつかのデータを表示しており、私はそれで動作する検索バーを取得しようとしています。検索は機能しますが、フィルタリングされたテーブルではなくフルテーブルからインデックスパスを使用してcontroller(didChangeObject:)が呼び出されるため、インデックスパスが範囲外であるため、更新によって間違ったレコードまたはエラーが修正されます。これがエラーの原因であることは分かっていますが、修正方法がわかりません。次のように私のコードの顕著な部分がある:NSFetchedResultsController UpdateをUISearchControllerで動作させるにはどうしたらいいですか?

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
    let cell = tableView.dequeueReusableCellWithIdentifier("PlayerTableViewCell", forIndexPath: indexPath) as! PlayerTableViewCell 
    let coreDataIndexPath: NSIndexPath 
    if searchController.active && searchController.searchBar.text != "" { 
     coreDataIndexPath = fetchedResultsController.indexPathForObject(filteredPlayers[indexPath.row])! 
    } else { 
     coreDataIndexPath = indexPath 
    } 
    configureCell(cell, atIndexPath: coreDataIndexPath) 
    return cell 
} 

override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { 
    if editingStyle == .Delete { 
     // Fetch Record 
     let record = fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject 

     // Delete Record 
     managedObjectContext.deleteObject(record) 
    } 
} 


// MARK: Fetched Results Controller Delegate Methods 
func controllerWillChangeContent(controller: NSFetchedResultsController) { 
    tableView.beginUpdates() 
} 

func controllerDidChangeContent(controller: NSFetchedResultsController) { 
    tableView.endUpdates() 
} 

func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { 
    switch (type) { 
    case .Insert: 
     if let indexPath = newIndexPath { 
      tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) 
     } 
    case .Delete: 
     if let indexPath = indexPath { 
      tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) 
     } 
    case .Update: 
     if let indexPath = indexPath { 
      let cell = tableView.cellForRowAtIndexPath(indexPath) as! PlayerTableViewCell 
      configureCell(cell, atIndexPath: indexPath) 
     } 
    case .Move: 
     if let indexPath = indexPath { 
      tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) 
     } 

     if let newIndexPath = newIndexPath { 
      tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade) 
     } 
    } 
} 

// MARK: UISearchResultsUpdating 
func updateSearchResultsForSearchController(searchController: UISearchController) { 
    if let searchText = searchController.searchBar.text { 
     let predicate = NSPredicate(format: "name CONTAINS %@", searchText) 
     if let fetchedObjects = fetchedResultsController.fetchedObjects as? [Player] { 
      filteredPlayers = fetchedObjects.filter({return predicate.evaluateWithObject($0)}) 
     } 
    } 
    tableView.reloadData() 

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
    if searchController.active && searchController.searchBar.text != "" { 
     return filteredPlayers.count 
    } else if let sections = fetchedResultsController.sections { 
     let sectionInfo = sections[section] 
     return sectionInfo.numberOfObjects 
    } 

    return 0 
} 

configureCellだけで細胞内へのindexPathでレコードからのデータをロードします。

私は以前にfetchedResultsController.fetchRequest.predicateを変更して検索を試みていましたが、私の最善の努力にもかかわらず、検索バーがキャンセルされたときにテーブルが正常に戻らなくなりました。次のようにこのコードはでした:

// MARK: UISearchResultsUpdating 
func updateSearchResultsForSearchController(searchController: UISearchController) { 
    let searchText = searchController.searchBar.text! 
    let predicate = NSPredicate(format: "%K CONTAINS[c] %@", argumentArray: ["name", searchText]) 
    fetchedResultsController.fetchRequest.predicate = predicate 
    do { 
     try self.fetchedResultsController.performFetch() 
    } catch { 
     let fetchError = error as NSError 
     print("\(fetchError), \(fetchError.userInfo)") 
    } 
    tableView.reloadData() 
} 

// MARK: UISearchBarDelegate 
func searchBarCancelButtonClicked(searchBar: UISearchBar) { 
    fetchedResultsController.fetchRequest.predicate = nil 
    do { 
     try self.fetchedResultsController.performFetch() 
    } catch { 
     let fetchError = error as NSError 
     print("\(fetchError), \(fetchError.userInfo)") 
    } 
    tableView.reloadData() 
} 
+0

あなたがこれを理解しましたか?私は同じ問題を抱えている。 – NRitH

答えて

1

は、あなたがここで行う必要がある2つのものがあります。

  • は、表データをリロードする前に、updateSearchResultsForSearchController内の各新しい検索イベントのNSFetchedResultsControllerをリセット。
  • cellForRowAtIndexPathをFRCのindexPathにあるセルとして返します。 NSFetchedResultsControllerは、searchBarの状態をポーリングする必要はありません。

私はまだのようスウィフト構文に慣れていないですが、ここではにObjCで次のようになります。

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


-(NSFetchedResultsController *)fetchedResultsController{ 
if (_fetchedResultsController == nil) { 
    NSManagedObjectContext *context = self.managedObjectContext; // Creating FRC with main MOC 

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:context]; 
    [fetchRequest setEntity:entity]; 

    NSString *searchString = [self.searchController.searchBar.text]; 
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name CONTAINS[cd] %@ ", searchString]; 

    [fetchRequest setPredicate:predicate]; 

    // Specify how the fetched objects should be sorted 
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"someField" ascending:YES]; 
    [fetchRequest setSortDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]]; 

    _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:nil]; 

    NSError *error = nil; 
    if (![_fetchedResultsController performFetch:&error]) 
     NSLog(@"Error initializing FRC for Users. Error %@", error.userInfo); 

    _fetchedResultsController.delegate = self; 
    } 
return _fetchedResultsController; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
     cell = [tableView dequeueReusableCellWithIdentifier:@"MyCell" forIndexPath:indexPath]; 

     if (cell == nil) 
       cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MyCell"]; 
     MyEntity *myObject = [self.fetchedResultsController objectAtIndexPath:indexPath]; 

    /* Populate cell content here */ 
    return cell; 
} 
+0

魅力的な作品です。ただのメモ。 self.searchControllerは、isActiveプロパティをテストできます。したがって、fetchedResultsController初期化部分には、ボディNSPredicate predicateWithFormatを持つself.searchController.isActiveの条件だけを含めることができます。 –

関連する問題