Основные данные: UITableView с несколькими NSFetchedResultControllers - PullRequest
26 голосов
/ 22 февраля 2010

То, что я хочу сделать, довольно просто. В моем UITableViewController я хочу загрузить данные из нескольких NSFetchedResultControllers (у меня есть несколько объектов в моей модели данных) и поместить данные каждого из них в отдельный раздел в табличном представлении. Так, например, все извлеченные элементы из первого NSFetchedResultController будут помещены в раздел 0 в UITableView, извлеченные элементы из другого - в раздел 1 и т. Д.

Шаблонный проект Core Data не демонстрирует, как это сделать. Все (в основном пути индекса) кодируется без учета разделов (в шаблоне по умолчанию нет разделов), а все берется из одного NSFetchedResultController. Есть ли примеры проектов или документации, которые демонстрируют это?

Спасибо

Ответы [ 3 ]

24 голосов
/ 22 февраля 2010

Предположим на минуту следующее в вашем заголовке (код ниже будет немного небрежным, мои извинения):

NSFetchedResultsController *fetchedResultsController1; // first section data
NSFetchedResultsController *fetchedResultsController2; // second section data

Сообщите таблице, что вы хотите иметь 2 раздела:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 2; // you wanted 2 sections
}

Дайте ему названия разделов:

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
    return [NSArray arrayWithObjects:@"First section title", @"Second section title", nil];
}

Пусть таблица знает, сколько строк в разделах:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (section == 0) {
        return [[fetchedResultsController1 fetchedObjects] count];
    } else if (section == 1) {
        return [[fetchedResultsController2 fetchedObjects] count];
    }

    return 0;
}

Построить ячейку:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    ... // table cell dequeue or creation, boilerplate stuff

    // customize the cell
    if (indexPath.section == 0) {
        // get the managed object from fetchedResultsController1
        // customize the cell based on the data
    } else if (indexPath.section == 1) {
        // get the managed object from fetchedResultsController2
        // customize the cell based on the data
    }

    return cell;
}
5 голосов
/ 07 марта 2017

Расширение решения Giao с помощью двух NSFetchedResultsController - мы должны помнить, что наш NSFetchedResultsController не знает о наших двух разделах, и возвращенные NSIndexPathes всегда будут для первого раздела.

Итак, когда мы получаем объект в конфигурации ячейки:

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
    if (!cell) {
        [tableView registerNib:[UINib nibWithNibName:@"cell" bundle:nil] forCellReuseIdentifier:@"cell"];
        cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
    }
    [self configureCell:cell atIndexPath:indexPath];
    return cell;
}

-(void)configureCell:(UITableViewCell*)cell atIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 0) {
        NSManagedObject *object = [self.fetchedResults1 objectAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row inSection:0]];
        //use object to configure cell
    } else {
        NSManagedObject *object = [self.fetchedResults2 objectAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row inSection:0]];
        //use object to configure cell
    }
}

Обновление ячеек, пока NSFetchedResultsController заметил некоторые изменения:

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
    NSIndexPath *customIndexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:(controller == self.fetchedResultsController1)?0:1];
    NSIndexPath *customNewIndexPath = [NSIndexPath indexPathForRow:newIndexPath.row inSection:(controller == self.fetchedResultsController2)?0:1];
    switch(type) {
        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:customNewIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:customIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
        case NSFetchedResultsChangeUpdate:
            [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
            break;
        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:customIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:customNewIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}
2 голосов
/ 18 октября 2017

Несколько контроллеров выборки (и, возможно, несколько объектов) - неправильный подход. Правильное решение - использовать параметр sectionNameKeyPath для NSFetchedResultController, чтобы сгруппировать результаты в несколько разделов. Если вы думаете о своих объектах по-разному, возможно, они на самом деле являются одним и тем же объектом, и вместо этого вы можете использовать свойство itemType, которое затем можно будет разделить (и вы также должны отсортировать его). Например. скажем, у меня были сущности Hops и Grains, тогда я мог бы изменить их на Ingredient и иметь свойство int_16 attributeType, которое затем я использовал в коде для перечисления значений hopType = 0, grainType = 1. Ведь ингредиент - это просто имя и вес, которые оба они разделяют.

Если, однако, ваши сущности действительно имеют отдельный набор свойств, то правильное решение состоит в том, чтобы создать родительскую абстрактную сущность, которая имеет свойство, которое вы можете использовать для секционирования, например, sortOrder, sectionID или тип. Затем, когда вы создаете контроллер выборки и извлекаете абстрактную родительскую сущность, вы фактически получаете результаты, содержащие все дочерние сущности. Например, в приложении Notes есть абстрактная сущность NoteContainer, в которой есть дочерние объекты Account и Folder. Таким образом, они могут использовать один контроллер выборки для отображения учетной записи в первой ячейке раздела, а затем иметь все папки в следующих ячейках. Например. Все iCloud Notes (на самом деле это учетная запись), затем Notes (это папка по умолчанию), затем все пользовательские папки, затем папка корзины. Они используют свойство sortOrder, папка по умолчанию - 1, все пользовательские папки - 2, а корзина - 3. Затем, добавив это в качестве дескриптора сортировки, они могут отображать ячейки в нужном им порядке. Это немного отличается от вашего требования, потому что у них есть 2 сущности, смешанные в разные секции, но вы все равно можете использовать его только с разными свойствами сортировки.

Мораль этой истории - не борись за рамки, обними ее: -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...