Подтвердить что ты не робот

Основные данные: UITableView с несколькими NSFetchedResultControllers

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

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

Спасибо

4b9b3361

Ответ 1

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

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;
}

Ответ 2

Расширение решения Giao с двумя NSFetchedResultsControllers - мы должны помнить, что наш 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;
    }
}

Ответ 3

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

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

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