Страницы

Поиск по вопросам

воскресенье, 15 декабря 2019 г.

Поиск по фетчу Core Dat'ы с использованием fetchedResultsController

#objective_c #ios #coredata


В наличии UITableView, контент которой заполняется из Core Data при помощи fetchedResultsController'а:
- (NSFetchedResultsController *) fetchedResultsController
{
    NSLog(@"fetchedResultsController");
    if (fetchedResultsController != nil)
    {
        return fetchedResultsController;
    }

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Client"
                                              inManagedObjectContext:[[PTDataManager
sharedManager] managedObjectContext]];
    [fetchRequest setEntity:entity];

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"agency_server_id
== %@", agency.server_id];
    fetchRequest.predicate = predicate;

    NSSortDescriptor *sortByName1Descriptor = [[NSSortDescriptor alloc] initWithKey:@"lastname"
ascending:YES];
    NSSortDescriptor *sortByName2Descriptor = [[NSSortDescriptor alloc] initWithKey:@"firstname"
ascending:YES];
    NSSortDescriptor *sortByName3Descriptor = [[NSSortDescriptor alloc] initWithKey:@"middlename"
ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects: sortByName1Descriptor,
sortByName2Descriptor, sortByName3Descriptor, nil];

    fetchRequest.sortDescriptors = sortDescriptors;

    fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:fetchRequest
managedObjectContext:[[PTDataManager sharedManager] managedObjectContext] sectionNameKeyPath:nil
cacheName:nil];
    fetchedResultsController.delegate = self;
    return fetchedResultsController;
}

другие делегатские методы не реализованы так как таблица заполняется один раз, при
входе во viewController и больше не меняется. Стоит задача реализовать поиск по контенту
таблицы с отображением в таблице только результатов соответствующих значениям введенным
в searchBar. Реализовываю метод:
   - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
    [self reloadTableView];
}

и соответственно триггеруемый метод для отображения в таблице:
- (void)reloadTableView
{
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Client"
                                              inManagedObjectContext:[[PTDataManager
sharedManager] managedObjectContext]];
    [fetchRequest setEntity:entity];

    NSPredicate *filterPredicate;
    NSString *searchString = self.searchBar.text;
    NSMutableArray *predicateArray = [[NSMutableArray alloc] init];
    [predicateArray addObject:[NSPredicate predicateWithFormat:@"agency_server_id
CONTAINS[cd] %@", agency.server_id]];
    [predicateArray addObject:[NSPredicate predicateWithFormat:@"firstname CONTAINS[cd]
%@", searchString]];
    [predicateArray addObject:[NSPredicate predicateWithFormat:@"lastname CONTAINS[cd]
%@", searchString]];
    [predicateArray addObject:[NSPredicate predicateWithFormat:@"middlename CONTAINS[cd]
%@", searchString]];
    filterPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:predicateArray];
    [fetchRequest setPredicate:filterPredicate];

    NSSortDescriptor *sortByName1Descriptor = [[NSSortDescriptor alloc] initWithKey:@"lastname"
ascending:YES];
    NSSortDescriptor *sortByName2Descriptor = [[NSSortDescriptor alloc] initWithKey:@"firstname"
ascending:YES];
    NSSortDescriptor *sortByName3Descriptor = [[NSSortDescriptor alloc] initWithKey:@"middlename"
ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects: sortByName1Descriptor,
sortByName2Descriptor, sortByName3Descriptor, nil];

    fetchRequest.sortDescriptors = sortDescriptors;
    fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:fetchRequest
managedObjectContext:[[PTDataManager sharedManager] managedObjectContext] sectionNameKeyPath:nil
cacheName:nil];
    fetchedResultsController.delegate = self;

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

    [self.clientsTableView reloadData];
}

который похож на fetchedResultsController но как видно имеется отличия в ограничении
выборки. Проблема в том, что в таком виде вызов -reloadTableView дергает и сам fetchedResultsController,
в результате фетч меняется в процессе ввода символов в searchBar. В таблице появляется
все что вытянул fetchedResultsController и плюс все остальное что совпадает с содержимым
searchBarа. Визуально: при вводе символов в поле поиска таблица не сокращает количество
результатов а увеличивает.
Вопрос:
на каком этапе реализации поиска по уже фетченой выборке я делаю ошибку? Могу ли
я как-то изменить вторичный фетч для поиска по уже полученным из первичного фетча результатам?    


Ответы

Ответ 1



Вопрос решился через составной предикат с использованием +orPredicateWithSubpredicates: и +andPredicateWithSubpredicates:: NSPredicate *orPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:[NSArray arrayWithObjects:firstPredicate, secondPredicate, nil]]; NSPredicate *andPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:thirdPredicate, fourthPredicate, nil]]; NSPredicate *finalPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:orPredicate, andPredicate, nil]]; [fetchRequest setPredicate:finalPredicate]; В таком виде через AND сохраняется результат предварительного фетча и через дополнительные OR происходит его фильтрация согласно критериям поиска

Ответ 2



Посмотрите первый ответ, похоже ваша ситуация: How to filter NSFetchedResultsController (CoreData) with UISearchDisplayController/UISearchBar

Комментариев нет:

Отправить комментарий