Sto cercando di implementare la ricerca nella mia app. Esistono due entità Core Data, "Tag" e "DvarTorah". Un tag ha solo una stringa. Un "DvarTorah" ha un titolo, un contenuto testuale e alcune altre proprietà. Sto cercando di capire il modo migliore per cercarli rapidamente. L'app viene fornita con circa 1200 entità DvarTorah e ancora più tag. In questo momento, carico un NSFetchedResultsController quando il mio controller della vista di ricerca chiama viewDidLoad. Quindi, quando l'utente digita nella casella di ricerca o modifica l'ambito, chiamo un metodo che accetta sia il valore della barra dell'ambito che un termine di ricerca e filtra la mia matrice di oggetti. Ecco come che sembra:Come posso ottimizzare questa ricerca basata su Core Data?
- (void) filterArrayWithSearchTerm:(NSString *)searchString andScopeIndex:(NSInteger)scopeIndex{
if ([searchString isEqualToString:@""]) {
return;
}
NSMutableArray *unfilteredResults = [[[[self.fetchedResultsController sections] objectAtIndex:0] objects] mutableCopy];
if (self.filteredArray == nil){
self.filteredArray = [[[NSMutableArray alloc ] init] autorelease];
}
[filteredArray removeAllObjects];
NSPredicate *predicate = [[[NSPredicate alloc] init] autorelease];
if (scopeIndex == 0) {
predicate = [NSPredicate predicateWithFormat:@"dvarTorahTitle CONTAINS[cd] %@", searchString];
}else if (scopeIndex == 1) {
predicate = [NSPredicate predicateWithFormat:@"searchableContent CONTAINS[cd] %@", [searchString canonicalString]];
}else if (scopeIndex == 2){
predicate = [NSPredicate predicateWithFormat:@"ANY tags.tagText CONTAINS[cd] %@", searchString];
}else{
predicate = [NSPredicate predicateWithFormat:@"(ANY tags.tagText CONTAINS[cd] %@) OR (dvarTorahTitle CONTAINS[cd] %@) OR (searchableContent CONTAINS[cd] %@)", searchString,searchString,searchString];
}
for (DvarTorah *dvarTorah in unfilteredResults) {
if ([predicate evaluateWithObject:dvarTorah]) {
[self.filteredArray addObject:dvarTorah];
}
}
[unfilteredResults release];
}
Il problema è che il mio metodo di ricerca è terribilmente lento. So che CONTAINS è un probabile colpevole, ma anche dopo aver archiviato una versione canonica del contenuto (come searchableContent) e aver tentato di ottimizzare ulteriormente, la ricerca è tremendamente lenta. Come posso renderlo più veloce?
Edit:
sulla base dei suggerimenti iniziali di Jacob, ecco il mio nuovo metodo:
if ([searchString isEqualToString:@""]) {
return;
}
if (self.filteredArray == nil) {
self.filteredArray = [[[NSMutableArray alloc ] init] autorelease];
}
[filteredArray removeAllObjects];
NSPredicate *predicate = nil;
if (scopeIndex == 0) {
predicate = [NSPredicate predicateWithFormat:@"dvarTorahTitle CONTAINS[cd] %@", searchString];
}else if (scopeIndex == 1) {
predicate = [NSPredicate predicateWithFormat:@"searchableContent CONTAINS[cd] %@", [searchString canonicalString]];
}else if (scopeIndex == 2){
predicate = [NSPredicate predicateWithFormat:@"ANY tags.tagText CONTAINS[cd] %@", searchString];
}else{
predicate = [NSPredicate predicateWithFormat:@"(ANY tags.tagText CONTAINS[cd] %@) OR (dvarTorahTitle CONTAINS[cd] %@) OR (searchableContent CONTAINS[cd] %@)", searchString,searchString,searchString];
}
[self.filteredArray addObjectsFromArray:[[[[[self.fetchedResultsController sections] objectAtIndex:0] objects] mutableCopy] filteredArrayUsingPredicate:predicate]];
}
Edit2:
Non copiare la matrice più, ancora lento:
- (void) filterArrayWithSearchTerm:(NSString *)searchString andScopeIndex:(NSInteger)scopeIndex{
if ([searchString isEqualToString:@""]) {
return;
}
if (self.filteredArray == nil) {
self.filteredArray = [[[NSMutableArray alloc ] init] autorelease];
}
[filteredArray removeAllObjects];
NSPredicate *predicate = nil;
if (scopeIndex == 0) {
predicate = [NSPredicate predicateWithFormat:@"dvarTorahTitle CONTAINS[cd] %@", searchString];
}else if (scopeIndex == 1) {
predicate = [NSPredicate predicateWithFormat:@"searchableContent CONTAINS[cd] %@", [searchString canonicalString]];
}else if (scopeIndex == 2){
predicate = [NSPredicate predicateWithFormat:@"ANY tags.tagText CONTAINS[cd] %@", searchString];
}else{
predicate = [NSPredicate predicateWithFormat:@"(ANY tags.tagText CONTAINS[cd] %@) OR (dvarTorahTitle CONTAINS[cd] %@) OR (searchableContent CONTAINS[cd] %@)", searchString,searchString,searchString];
}
[self.filteredArray addObjectsFromArray:[[[[self.fetchedResultsController sections] objectAtIndex:0] objects] filteredArrayUsingPredicate:predicate]];
}
sono tutti quattro versioni altrettanto lento? Quanto è grande il set di risultati che stai filtrando? Potresti cavartela usando qualcosa di diverso da quello che contiene? –
@ DavidRönnqvist - Il set di risultati è di circa 1200 oggetti. Forse sto fraintendendo il UISearchResultsController del tutto ... Per quanto riguarda la lentezza comparativa, sto profilando a occhio, non usando uno strumento, quindi non ne sono sicuro. Sembra lo stesso per me. – Moshe