Как программно переключить NSFetchedResultsController UITableView (или его предикат)?
У меня есть UITableView, который отображает подмножество большого количества объектов с именем "документы". Подмножество определяется другой сущностью "Selection". Выборка именуется, упорядочивается список документов.
Это работает нормально, за исключением тех случаев, когда я хочу изменить отображаемый выбор во время выполнения. Я получаю только пустой список.
В принципе, мне нужно изменить предикат, который содержит мой 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 fetch request - updating predicate и UITableView
И ответ был: чтобы избавиться от NSFetchedResultsController. Я не хочу этого делать, потому что NSFetchedResultsController приносит много полезных полезностей (например, кэширование, частичная загрузка...). Вопрос все еще стоит: как "переключить" данные в UITableView, поддерживаемом NSFetchedResultsController, где" переключить " означает иметь другой предикат или даже (не в моем случае) другую сущность.
Отметим для полноты, что поскольку отношение "многие-ко-многим" от выбора к документу является упорядоченный, он обрабатывается через промежуточную облегченную сущность, называемую DocInSelection, которая имеет свойство "упорядочивание" и два отношения "многие к одному" для документа и выбора.
Спасибо за любое предложение.
4 ответа:
Поскольку NSFetchedResultsController (FRC) является объектом, вы можете хранить его экземпляры, как и любой другой объект.
Один полезный метод состоит в том, чтобы инициализировать и сохранить несколько FRC в словаре, а затем установить атрибут
fetchedResultController
контроллера tableview на нужный вам в данный момент FRC. Это полезно в таких ситуациях, как сегментированный элемент управления для сортировки по различным атрибутам или сущностям в одной таблице. Этот метод имеет преимущество в поддержании отдельных кэшей FRC, которые может ускорить получение значительно.Просто убедитесь, что вы отправили самому tableview
beginUpdates
, Прежде чем поменять контроллеры, а затемendUpdates
, Когда вы закончите. Это не позволяет таблице запрашивать данные в узком окне при замене FRC. Затем вызовитеreloadData
.
После того, как я опубликовал свой вопрос, я попробовал вариант кода, который показал ОП другого вопроса. Это работает на меня. Вот ОНО:
- (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]; }
Хотя это может сработать, в справочной библиотеке iOS есть заметка, которая меня беспокоит:
Важно: вы не должны изменять запрос на получение. Например, вы должны не менять свой предикат или вид предварительные заявки.
Источник: Ссылка На Класс NSFetchedResultsController
Это дополнительное Примечание отсутствует в справочной библиотеке iOS 3.2.
Просто хотел указать на это.