2

У меня есть управляемый объект с атрибутом dueDate. Вместо отображения с помощью какой-то уродливой строки даты, как заголовки разделов моего UITableView Я создал переходный атрибут «категория» и определил его следующим образом:Имя пользовательского раздела Crashing NSFetchedResultsController

- (NSString*)category 
{ 
    [self willAccessValueForKey:@"category"]; 

    NSString* categoryName; 
    if ([self isOverdue]) 
    { 
     categoryName = @"Overdue"; 
    } 
    else if ([self.finishedDate != nil]) 
    { 
     categoryName = @"Done"; 
    } 
    else 
    { 
     categoryName = @"In Progress"; 
    } 

    [self didAccessValueForKey:@"category"]; 
    return categoryName; 
} 

Вот NSFetchedResultsController настройки:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Task" 
              inManagedObjectContext:managedObjectContext]; 
[fetchRequest setEntity:entity]; 

NSMutableArray* descriptors = [[NSMutableArray alloc] init]; 
NSSortDescriptor *dueDateDescriptor = [[NSSortDescriptor alloc] initWithKey:@"dueDate" 
                    ascending:YES]; 
[descriptors addObject:dueDateDescriptor]; 
[dueDateDescriptor release]; 
[fetchRequest setSortDescriptors:descriptors]; 

fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:@"category" cacheName:@"Root"]; 

Вначале таблица выглядит нормально, показывая незавершенные предметы, чья должная дата не прошла в разделе «Выполняется». Теперь пользователь может нажать строку в представлении таблицы, которая подталкивает новое представление сведений в стек навигации. В этом новом представлении пользователь может нажать кнопку, чтобы указать, что элемент теперь «Готово». Вот обработчик для кнопки (self.task является управляемый объект):

- (void)taskDoneButtonTapped 
{ 
    self.task.finishedDate = [NSDate date]; 
} 

Как только значения «finishedDate» изменения атрибутов я попал с этим исключением:

2010-03-18 23:29:52.476 MyApp[1637:207] Serious application error. Exception was caught during Core Data change processing: no section named 'Done' found with userInfo (null) 
2010-03-18 23:29:52.477 MyApp[1637:207] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'no section named 'Done' found' 

Мне удалось выяснить, что UITableView, который в настоящее время скрыт в новом представлении деталей, пытается обновить свои строки и разделы, потому что NSFetchedResultsController был уведомлен о том, что что-то изменилось в наборе данных. Вот мой код обновления таблицы (копируется из любого образца Основных Рецептов данных или образца CoreBooks - я не помню, какие):

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller 
{ 
    [self.tableView beginUpdates]; 
} 

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath 
{ 
    switch(type) 
    { 
     case NSFetchedResultsChangeInsert: 
      [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 

     case NSFetchedResultsChangeDelete: 
      [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 

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

     case NSFetchedResultsChangeMove: 
      [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      // Reloading the section inserts a new row and ensures that titles are updated appropriately. 
      [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:newIndexPath.section] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 
    } 
} 

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type 
{ 
    switch(type) 
    { 
     case NSFetchedResultsChangeInsert: 
      [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 

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

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller 
{ 
    [self.tableView endUpdates]; 
} 

Я ставлю точки останова в каждом из этих функций и обнаружил, что только controllerWillChange называется , Исключение выбрано перед любым контроллером: didChangeObject: atIndexPath: forChangeType: newIndex или controller: didChangeSection: atIndex: forChangeType вызывается.

На данный момент я застрял. Если я изменил свой разделNameKeyPath на просто «dueDate», тогда все будет хорошо. Я думаю, это потому, что атрибут dueDate никогда не изменяется, тогда как категория будет отличаться при чтении после изменения атрибута finalDate.

Пожалуйста, помогите!

UPDATE:

Вот мой UITableViewDataSource код:

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

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

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

    UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
    if (cell == nil) 
    { 
     cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 
    } 

    [self configureCell:cell atIndexPath:indexPath];  

    return cell; 
} 

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section 
{ 
    id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];  
    return [sectionInfo name]; 
} 

ответ

1

Он смотрит на меня, как ваша проблема лежит с «категории» переходная собственность, которую вы используете для питания sectionNameKeyPath. РазделNameKeyPath должен заказывать то же самое, что и основной дескриптор сортировки. В вашем случае это означает, что все «просроченные» задания ДОЛЖНЫ иметь даты раньше, чем все задачи «Готово» ДОЛЖНЫ иметь даты раньше, чем все задачи «Выполнение». Можно построить сценарий, в котором задача «Готово» имеет значение DueDate, которое приходит после задачи «Выполняется» или предшествует задаче «Просрочка». Этот сценарий нарушает требование упорядочения разделаNameKeyPath и заставляет NSFetchedResultsController вызывать исключение NSInternalConsistencyException.

Я предлагаю решение вашей проблемы, которое не связано с переводом собственного массива, который затем должен быть разделен на разделы. Создайте в своей модели целочисленный атрибут, в котором вы нажмете 0 на «Просрочка», 1 на «Готово» и 2 на «Выполняется». Сделайте это основным дескриптором сортировки в вашем NSFetchRequest и отсортируйте это свойство в порядке возрастания. Добавьте вторичный дескриптор сортировки в NSFetchRequest, который сортирует свойство dueDate в порядке возрастания.Измените метод категории, чтобы получить имена категорий из целочисленного атрибута, который вы создали выше, и используйте его как свой разделNameKeyPath. Вам необходимо будет обновить целочисленный атрибут для обновления задач по мере их перехода от процесса до просрочки до конца и т. Д.

+1

Я почтительно не согласен с Маркусом - я не думаю, что это ошибка. В документации для NSFetchedResultsController говорится: «Запрос на выборку должен иметь по крайней мере один дескриптор сортировки. Если контроллер генерирует разделы, первый дескриптор сортировки в массиве используется для группировки объектов в разделы, его ключ должен либо быть таким же, как sectionNameKeyPath или относительное упорядочение с использованием его ключа должно совпадать с использованием sectionNameKeyPath. " Как я вижу, происходит сбой, потому что ключ для дескриптора сортировки и ключ для разделаNameKeyPath имеют разные порядки сортировки. – glorifiedHacker

+0

Очень интересное предложение. Имеет смысл в зависимости от того, что я прочитал из документов SDK. Я уже пошел по пути создания отдельного массива, но я посмотрю, смогу ли я попробовать попробовать в какой-то момент. Благодаря! –

2

Аварийный сигнал вызван NSFetchedResultsController, который не знает о «готовой» категории перед ручным и, следовательно, сбой. Я видел этот крах несколько раз в других вопросах, и с каждым из них я рекомендую отправить радиолокационный билет в Apple. Это ошибка в NSFetchedResultsController.

+0

Просто наткнулся на этот вопрос, потому что мое приложение падает под iOS 3 именно по этой причине, но не под iOS 4. Вам придется найти обходное решение или отказаться от поддержки 3.x ... – Pascal

Смежные вопросы