Как программно переключить NSFetchedResultsController в UITableView (или его предикат)? - PullRequest
3 голосов
/ 16 августа 2010

У меня есть UITableView, который отображает подмножество большого количества объектов с именем «Документы». Подмножество определяется другим объектом «Выбор». Выборы названы, упорядочен список документов.

Работает нормально, кроме случаев, когда я хочу изменить отображаемый выбор во время выполнения. Я получаю только пустой список.

По сути, мне нужно изменить предикат, который хранит мой NSFetchedResultsController, чтобы новый предикат использовал другой выбор. Я не мог заставить это работать. Моя последняя попытка - полностью избавиться от NSFetchedResultsController и перераспределить его:

- (void) displaySelection:(Selection *)aSet
{
 self.currentSelection = aSet;
 self.fetchedResultsController = nil;
 // methods here don't all use the property but directly the ivar, so we must trigger the getter
 [self fetchedResultsController];
 [self.tableView reloadData];
}

И, конечно, средство получения NSFetchedResultsController делает правильные вещи:

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

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"DocInSelection" inManagedObjectContext:managedObjectContext];
    [fetchRequest setEntity:entity];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"selection.identifier like %@", currentSelection.identifier];
    [fetchRequest setPredicate:predicate];
<snip>
    [fetchRequest setSortDescriptors:sortDescriptors];
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:@"Root"];
    aFetchedResultsController.delegate = self;
    self.fetchedResultsController = aFetchedResultsController;
<snip>
    return fetchedResultsController;
}

Этот код работает в первый раз, потому что установлен Начальный выбор. Однако при вызове displaySelection: табличное представление становится пустым.

Очень похожий вопрос был задан в NSFetchedResultsController запрос на выборку - обновление предиката и UITableView

И ответом было избавиться от NSFetchedResultsController. Я не хочу этого делать, потому что NSFetchedResultsController приносит много полезных полезностей (например, кеширование, частичная загрузка ...). До сих пор остается вопрос: как «переключать» данные в UITableView, поддерживаемом NSFetchedResultsController, где «переключатель» означает наличие другого предиката или даже (не в моем случае) другого объекта.

Заметьте, ради полноты, что поскольку упорядочено отношение «многие ко многим» из «Выделения в документ», оно обрабатывается через промежуточную легковесную сущность под названием DocInSelection, которая имеет свойство «упорядочения» и два множества. отношения один к одному с документом и выбором.

Спасибо за любые предложения.

Ответы [ 4 ]

15 голосов
/ 16 августа 2010

Поскольку NSFetchedResultsController (FRC) является объектом, вы можете хранить его экземпляры, как и любой другой объект.

Один из полезных методов - инициализировать и сохранить несколько FRC в словаре, а затем установить атрибут fetchedResultController контроллера табличного представления на FRC, который вам нужен в данный момент. Это полезно для ситуаций, таких как наличие сегментированного элемента управления для сортировки по различным атрибутам или объектам в одной таблице. Преимущество этого метода заключается в поддержании отдельных кэшей FRC, которые могут значительно ускорить выборку.

Просто обязательно отправьте саму таблицу beginUpdates перед тем, как поменять контроллеры, а затем endUpdates, когда вы закончите. Это не позволяет таблице запрашивать данные в узком окне при замене FRC. Затем позвоните reloadData.

6 голосов
/ 16 августа 2010

После того как я отправил свой вопрос, я попробовал вариант кода, который показывал ОП другого вопроса.Меня устраивает.Вот оно:

- (void) displaySelection:(Selection *)aSet
{
    if (aSet != self.currentSelection) {
        self.currentSelection = aSet;

        NSFetchRequest *fetchRequest = [[self fetchedResultsController] fetchRequest];
        NSPredicate *predicate = nil;
        NSEntityDescription *entity = nil;
        entity = [NSEntityDescription entityForName:@"DocInSelection" inManagedObjectContext:managedObjectContext];
        predicate = [NSPredicate predicateWithFormat:@"selection.identifier like %@", currentSelection.identifier];
        [fetchRequest setEntity:entity];
        [fetchRequest setPredicate:predicate];

        [NSFetchedResultsController deleteCacheWithName:@"Root"];

        NSError *error = nil;
        if (![[self fetchedResultsController] performFetch:&error]) {
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }       
    }
    [self.tableView reloadData];
}
3 голосов
/ 16 сентября 2010

Хотя это может работать, в справочной библиотеке iOS есть примечание, которое меня беспокоит:

Внимание: Вы не должны изменять запрос на выборку.Например, вы не должны изменять его предикат или порядок сортировки.

Источник: NSFetchedResultsController Справочник по классам

Эта дополнительная заметка не существует в iOS3.2 Справочная библиотека.

Просто хотел указать на это.

0 голосов
/ 03 мая 2011

Важное замечание: если вы «перезаписываете» объект fetchController, убедитесь, что вы сначала очистили его .delegate - в противном случае вы получите сбой при удалении строк и т. Д., Как старый fetchController и его делегат получат события.

...