2009-09-13 8 views
17

Quelle est la meilleure pratique pour filtrer les données NSFetchedResultsController? ai-je besoin de le réinitialiser chaque fois que le texte de la barre de recherche change?NSFetchedResultsController with search

J'utilise un UISearchDisplayControllers et je suis mise en œuvre:

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString; 

Thx.

+0

Comment avez-vous fini par gérer les méthodes de source de données de vue table afin que la vue de table sache ou non afficher la «liste filtrée»? – CraigH

+1

La réponse ici est très très utile http://stackoverflow.com/questions/4471289/how-to-filter-nsfetchedresultscontroller-coredata-with-uisearchdisplaycontroll/4481896#4481896 – acecapades

+0

Voici ce que j'ai fait: http: // stackoverflow .com/questions/4471289/comment-filtrer-nsfetchedresultscontroller-coredata-avec-uisearchdisplaycontrolle/4856118 # 4856118 –

Répondre

17

Comment est le code de réponse de Guy différente de la question? Pour autant que je puisse le deviner, la méthode filterContentForSearchText: scope est appelée par les méthodes shouldReload?

De toute façon, voici un code similaire que j'ai ajouté dans l'exemple CoreDataBooks pour inclure la recherche. Ajoutez un contrôleur d'affichage de recherche dans IB pour l'exemple CoreDataBooks. Puis j'ai ajouté le code à RootViewController.m comme suit:

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString { 
NSInteger searchOption = controller.searchBar.selectedScopeButtonIndex; 
return [self searchDisplayController:controller shouldReloadTableForSearchString:searchString searchScope:searchOption]; 
} 

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption { 
NSString* searchString = controller.searchBar.text; 
return [self searchDisplayController:controller shouldReloadTableForSearchString:searchString searchScope:searchOption]; 
} 

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString*)searchString searchScope:(NSInteger)searchOption { 

NSPredicate *predicate = nil; 
if ([searchString length]) 
    if (searchOption == 0) // full text, in my implementation. Other scope button titles are "Author", "Title" 
    predicate = [NSPredicate predicateWithFormat:@"title contains[cd] %@ OR author contains[cd] %@", searchString, searchString]; 
    else 
    // docs say keys are case insensitive, but apparently not so. 
    predicate = [NSPredicate predicateWithFormat:@"%K contains[cd] %@", [[controller.searchBar.scopeButtonTitles objectAtIndex:searchOption] lowercaseString], searchString]; 
[fetchedResultsController.fetchRequest setPredicate:predicate]; 

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

return YES; 
} 

PS. Pour répondre à Vivas, en utilisant un UISearchDisplayController, il crée automatiquement une nouvelle vue de table pour superposer la liste filtrée. Vous pouvez vérifier quelle tableView est utilisée comme indiqué dans les docs, mais dans la configuration la plus simple, cela fonctionne simplement parce que fetchedResultsController affiche une version filtrée dans la vue tableau de la recherche ou affiche toutes les données dans votre vue tabulaire.

+0

Toujours un comportement étrange ... les objets sont filtrés, mais quand je fais défiler la vue de la table, cela donne une exception, car fetchController n'a pas d'objet à index particulier ... qu'est-ce qui peut être faux? S'il vous plaît, aide –

+0

J'ai trouvé mon problème ... quand je reçois les résultats filtrés, ils sont affichés dans le tableauView configuré de la même manière et quand je fais défiler jusqu'à la ligne numéro X où le nombre réel de lignes est plus petit que X ... devrais-je.. –

8

Appearantly ceci est une meilleure façon:

- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope 
{ 
    self.savedSearchTerm = searchText; 

    freshData = NO; 
    if (searchText !=nil) 
    { 
      NSPredicate *predicate =[NSPredicate predicateWithFormat:@"name contains[cd] %@", searchText]; 
      [fetchedResultsController.fetchRequest setPredicate:predicate]; 
    } 
    else 
    { 
      NSPredicate *predicate =[NSPredicate predicateWithFormat:@"All"]; 
      [fetchedResultsController.fetchRequest setPredicate:predicate]; 
    } 

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

    [self.tableView reloadData]; 

    // [searchBar resignFirstResponder]; 
    // [_shadeView setAlpha:0.0f]; 

} 
+29

exit (-1) est un peu dur. – 0xced

+5

Les appl docs indiquent que la requête d'extraction ne doit pas être modifiée - ils indiquent spécifiquement que vous ne devez pas modifier le prédicat. –

+1

@RogerNolan Etes-vous sûr? Extrayez [Référence de la classe NSFetchedResultsController: Modification de la requête d'extraction] (http://j.mp/z3W7QK). Ces trois étapes fonctionnent bien pour moi, et je modifie même le prédicat de la requête d'extraction. – ma11hew28