Пустые разделы sortDescriptors и table view

В разделах таблиц и sortDescriptors есть что-то, что сводит меня с ума. Любая помощь будет высоко ценится ;)

Я ищу просто отображение строки «добавить» внизу каждого раздела self.fetchedResultsController.fetchedObjects. Я использую sectionNameKeyPath для отображения разделов в моем табличном представлении. До сих пор все работает отлично. Я реализовал эту технику в других частях своего приложения и работает довольно хорошо.

Однако проблема возникает, когда FRC не возвращает данных, а основные данные не возвращают никакой сущности. Если я попытаюсь добавить свой первый управляемый объект, приложение выйдет из строя со следующей ошибкой:

Количество разделов, содержащихся в табличном представлении после обновления (1), должно быть равно количеству разделов, содержащихся в табличном представлении до обновления (1), плюс или минус количество вставленных или удаленных разделов (1 вставлено, 0 удалено). с userInfo (null)

Это мой код на данный момент:

    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    if ([self.fetchedResultsController.fetchedObjects count] == 0) {
        return 1;
    }
   return [[self.fetchedResultsController sections] count];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // Return the number of rows in the section.

    if ([self.fetchedResultsController.fetchedObjects count] == 0) {
        return 1;
    }
    id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];

    return [sectionInfo numberOfObjects] + 1;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

    if ([self.fetchedResultsController.fetchedObjects count] == 0 ) {

        static NSString *identificadorCelda2 = @"CeldaNuevoGasto";
        UITableViewCell *celda = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:identificadorCelda2];
        if (celda == nil) {
            celda = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:identificadorCelda2];
        }
        return celda;
    }

    id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:indexPath.section];

    NSInteger nsection = [sectionInfo numberOfObjects];

    if (indexPath.row == nsection) {

        static NSString *identificadorCelda2 = @"CeldaNuevoGasto";
        UITableViewCell *celda = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:identificadorCelda2];
        if (celda == nil) {
            celda = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:identificadorCelda2];
        }        
        return celda;
    }

    static NSString *CellIdentifier = @"CeldaGasto";

    CeldaGastos *cell = (CeldaGastos *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) {
        cell = (CeldaGastos *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    } .....

Я точно что-то делаю не так, но пока не могу понять. Нужно ли мне изменять методы делегата NSFetchedResultsController, чтобы отвечать на добавления? Или это что-то более легкое. Спасибо ;)

Обновить

    - (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
           atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{

    NSInteger nsection = [self.fetchedResultsController.sections count];
    switch(type) {
        case NSFetchedResultsChangeInsert:
            if (nsection == 1 && [sectionInfo numberOfObjects] == 1) {
                    [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];

            }
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:

            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];

            if (!nsection)
                [self.tableView insertSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

person sam80    schedule 05.11.2012    source источник


Ответы (1)


Если я правильно понимаю вашу ситуацию, вам действительно придется изменить методы делегата NSFetchedResultsController.

Вы вставляете новые разделы в представление таблицы, используя метод -insertSections:withRowAnimation: представления таблицы из некоторых обратных вызовов делегата NSFetchedResultsController?

Я не знаю точно, какова ваша реализация NSFetchedResultsControllerDelegate, но, например, рассмотрим эту ситуацию шаг за шагом:

  1. Изначально у вас не было извлеченных сущностей, и ваш -numberOfSectionsInTableView: метод возвращает 1 для вашей строки «добавить».

  2. После того, как вы вставили объект, и делегат NSFetchedResultsController получает свой -controller:didChangeSection:atIndex:forChangeType: обратный вызов, в котором вы вставляете новый раздел в представление таблицы, используя -insertSections:withRowAnimation:

  3. Табличное представление запрашивает свой источник данных, вызывая метод -numberOfSectionsInTableView:, ожидая, что он вернет значение, увеличенное на 1 (поскольку вы вставляете 1 новый раздел). Но метод по-прежнему возвращает 1, потому что строка «добавить» больше не учитывается.

Это приведет именно к той ошибке, которую вы имеете.

Я предполагаю, что вызов -deleteSections:withRowAnimation: для удаления строки «добавить», когда она больше не нужна, решит вашу проблему.

person Egor Chiglintsev    schedule 05.11.2012
comment
Спасибо wanderwaltz за вашу помощь, это очень помогло. Теперь проблема возникает при удалении :(. Если вы посмотрите на мой метод в обновлении выше, вы поймете, о чем я говорю. Я получаю следующую ошибку: *** - [__ NSArrayM objectAtIndex:]: index 0 вне пределов для пустого массива с userInfo (null) Я попытаюсь найти ответ сам, но ваша помощь будет оценена, ура - person sam80; 06.11.2012
comment
Появляется ли новая ошибка, когда вы удаляете последний (и единственный) раздел табличного представления, или когда есть несколько разделов, и один из них удален? Я не уверен, но похоже, что если есть, например, 2 раздела, и вы пытаетесь удалить первый (у него индекс 0), то ваш обновленный код попытается удалить этот раздел дважды (поскольку 'if (sectionIndex == 0) 'в этом случае будет выполнено условие). Может, лучше не проверять индекс раздела, а фактическое общее количество разделов при добавлении / удалении строки «добавить»? - person Egor Chiglintsev; 06.11.2012
comment
Я обновил метод didChangeSection до своей последней версии, пожалуйста, посмотрите;). Он отлично работает, за исключением случая наличия 1 раздела и 1 строки :( где он прерывается с ошибкой: - [__ NSArrayM objectAtIndex:]: индекс 0 за пределами границ для пустого массива с userInfo (null) - person sam80; 06.11.2012
comment
Хм, в случае 1 раздела и 1 строки ваш код по-прежнему вызывает удаление и вставку для того же индекса раздела (поскольку раздел 0 удаляется, а строка 'add' снова вставляется с разделом 0) Может быть ошибка появляется из-за этого? В качестве опции вы можете обнаружить случай «1 раздел 1 строка» и не делать никаких вставок / удалений из представления таблицы (поскольку структура представления таблицы останется прежней - 1 раздел, 1 строка), но просто перезагрузите это единый раздел с правильной анимацией. - person Egor Chiglintsev; 06.11.2012
comment
После глубокой отладки кода я нашел неправильный путь. Это произошло из метода делегата таблицы commitEditingStyle. Он сломался при попытке сохранить контекст. Решением было переместить [self.managedObjectContext save: & error] в didChangeObject :. Теперь он работает отлично, но я не уверен, что это лучший способ сделать это. Классная помощь с вашей стороны wanderwaltz;) - person sam80; 06.11.2012