numberOfRowsInSection: метод для основных данных и нескольких разделов.

Я пытаюсь показать табличное представление с двумя разделами. В первом разделе всегда будет 1 строка, а во втором разделе будет столько строк, сколько точек данных. Я использую Core Data и следующий метод tableView:numberOfRowsInSection:...

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (section == 0) {
        return 1;
    } else {
        id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
        return [sectionInfo numberOfObjects];
    }
}

Однако я получаю следующую ошибку:

Завершение работы приложения из-за необработанного исключения «NSRangeException», причина: «* -[__NSArrayM objectAtIndex:]: индекс 1 за пределами [0 .. 0]»

Любая помощь будет оценена. Спасибо.

НОВЫЙ ------------------------------------------------- ------------------------------

Это текущая реализация соответствующих методов:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (section == 0) {
        return 1;
    } else {
        NSUInteger frcSection = section - 1;
        id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:frcSection];
        return [sectionInfo numberOfObjects];
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }

    [self configureCell:cell atIndexPath:indexPath];
    return cell;
}

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.section == 0) {
        cell.textLabel.text = entityOne.name;  //entityOne object passed from previous VC
    } else {
        entityTwo = [self.fetchedResultsController objectAtIndexPath:indexPath];
        cell.textLabel.text = entityTwo.name;
    }
}

- (void)controller:(NSFetchedResultsController *)controller
  didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
           atIndex:(NSUInteger)sectionIndex
     forChangeType:(NSFetchedResultsChangeType)type
{
    NSUInteger frcSectionIndex = 0;
    frcSectionIndex = sectionIndex + 1;

    switch(type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:frcSectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:frcSectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

- (void)controller:(NSFetchedResultsController *)controller
   didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath *)indexPath
     forChangeType:(NSFetchedResultsChangeType)type
      newIndexPath:(NSIndexPath *)newIndexPath
{
    UITableView *tableView = self.tableView;

    switch(type) {
        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeUpdate:
            [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
            break;

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

person AveLeon    schedule 13.01.2013    source источник


Ответы (1)


Причина в том, что контроллер извлеченных результатов (FRC) имеет только один раздел (раздел №0), который вы хотите отобразить во втором разделе (раздел №1). представления таблицы.

Это возможно, но вы должны сопоставить номера разделов FRC и номера разделов табличного представления, например.

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (section == 0) {
        return 1;
    } else {
        NSUInteger frcSection = section - 1;
        id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:frcSection];
        return [sectionInfo numberOfObjects];
    }
}

Такое же отображение необходимо в cellForRowAtIndexPath.

В методах делегата FRC didChangeObject, didChangeSection необходимо добавить 1 к номеру раздела перед вызовом методов табличного представления (например, insertRowsAtIndexPaths).


ДОБАВЛЕНО: configureCell должно выглядеть так:

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.section == 0) {
        cell.textLabel.text = entityOne.name;  //entityOne object passed from previous VC
    } else {
        NSIndexPath *frcIndexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:(indexPath.section - 1)];
        entityTwo = [self.fetchedResultsController objectAtIndexPath:frcIndexPath];
        cell.textLabel.text = entityTwo.name;
    }
}

и didChangeObject вот так:

- (void)controller:(NSFetchedResultsController *)controller
   didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath *)indexPath
     forChangeType:(NSFetchedResultsChangeType)type
      newIndexPath:(NSIndexPath *)newIndexPath
{
    UITableView *tableView = self.tableView;
    NSIndexPath *tvIndexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:(indexPath.section + 1)];
    NSIndexPath *tvNewIndexPath = [NSIndexPath indexPathForRow:newIndexPath.row inSection:(newIndexPath.section + 1)];

    switch(type) {
        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:@[tvNewIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:@[tvIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeUpdate:
            [self configureCell:[tableView cellForRowAtIndexPath:tvIndexPath] atIndexPath:tvIndexPath];
            break;

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:@[tvIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:@[tvNewIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

Вы, вероятно, поняли идею:

  • При переходе от пути индекса FRC к пути индекса табличного представления добавьте один в раздел.
  • При переходе от пути индекса табличного представления к пути индекса FRC вычтите единицу из раздела.
person Martin R    schedule 13.01.2013
comment
Спасибо. Как вы объяснили, мне удалось выполнить сопоставление в методах numberOfRowsInSection: и didChangeSection:. Однако мне трудно выполнить сопоставление в методах cellForRowAtIndexPath: и didChangeObject:. Не могли бы вы помочь мне с этими двумя сопоставлениями? - person AveLeon; 13.01.2013
comment
@AveLeon: Если вы добавите свою текущую реализацию этих функций к своему вопросу, я могу попытаться помочь. - person Martin R; 13.01.2013
comment
Спасибо. Я только что сделал. Как вы увидите, мне не удалось изменить номер раздела в методах с путями к индексу. - person AveLeon; 13.01.2013
comment
Большое спасибо! Это конечно помогло! - person AveLeon; 13.01.2013
comment
Вопрос: вы намеренно оставили indexPath нетронутым в случае NSFetchedResultsChangeUpdate? - person AveLeon; 13.01.2013
comment
@AveLeon: Нет, это была ошибка с моей стороны, извините. Я исправил ответ. - person Martin R; 13.01.2013