Iphone 自定义节名崩溃NSFetchedResultsController

Iphone 自定义节名崩溃NSFetchedResultsController,iphone,uitableview,core-data,nsfetchedresultscontroller,Iphone,Uitableview,Core Data,Nsfetchedresultscontroller,我有一个具有dueDate属性的托管对象。我创建了一个名为“category”的临时属性,并将其定义为: - (NSString*)category { [self willAccessValueForKey:@"category"]; NSString* categoryName; if ([self isOverdue]) { categoryName = @"Overdue"; } else if ([self.finish

我有一个具有dueDate属性的托管对象。我创建了一个名为“category”的临时属性,并将其定义为:

- (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"];
表格最初显示fine,在标题为“进行中”的部分中显示dueDate未超过的未完成项目。现在,用户可以点击表视图中的一行,将新的详细信息视图推送到导航堆栈上。在这个新视图中,用户可以点击一个按钮来指示项目现在已“完成”。下面是按钮的处理程序(self.task是托管对象):

一旦“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收到了数据集中发生更改的通知。以下是我的表更新代码(复制自Core Data Recipes样本或CoreBooks样本——我记不清是哪一个):

-(void)controllerWillChangeContent:(NSFetchedResultsController*)控制器
{
[self.tableView开始更新];
}
-(void)控制器:(NSFetchedResultsController*)控制器didChangeObject:(id)索引路径中的一个对象:(NSIndexPath*)变更类型的indexPath:(NSFetchedResultsChangeType)类型newIndexPath:(NSIndexPath*)newIndexPath
{
开关(类型)
{
案例NSFetchedResultsChangesInsert:
[self.tableView insertRowsAtIndexPaths:[NSArray arraywhithobject:newindexath]with rownanimation:uitableviewrownanimationfade];
打破
案例NSFetchedResultsChangeDelete:
[self.tableView deleteRowsatindExpath:[NSArray arrayWithObject:indexPath]带RowAnimation:UITableViewRowAnimationFade];
打破
案例NSFetchedResultsChangeUpdate:
[self-configureCell:[self.tableView CellForRowatineXpath:indexPath]AtiXpath:indexPath];
打破
案例NSFetchedResultsChangeMove:
[self.tableView deleteRowsatindExpath:[NSArray arrayWithObject:indexPath]带RowAnimation:UITableViewRowAnimationFade];
//重新加载节将插入新行,并确保标题得到适当更新。
[self.tableView重新加载节:[NSIndexSet indexetwithindex:newIndexPath.section]带行动画:UITableViewRowAnimationFade];
打破
}
}
-(void)控制器:(NSFetchedResultsController*)控制器didChangeSection:(id)sectionInfo atIndex:(nsInteger)ChangeType的sectionIndex:(NSFetchedResultsChangeType)类型
{
开关(类型)
{
案例NSFetchedResultsChangesInsert:
[self.tableView insertSections:[NSIndexSet IndexSetWithiIndex:sectionIndex]带RowAnimation:UITableViewRowAnimationFade];
打破
案例NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet IndexSetWithiIndex:sectionIndex]带RowAnimation:UITableViewRowAnimationFade];
打破
}
}
-(void)controllerDidChangeContent:(NSFetchedResultsController*)控制器
{
[self.tableView endUpdates];
}
我在每个函数中都设置了断点,发现只调用了controllerWillChange。在调用控制器:didChangeObject:atIndexPath:forChangeType:newIndex或控制器:didChangeSection:atIndex:forChangeType之前引发异常

在这一点上,我被卡住了。如果我将sectionNameKeyPath更改为“dueDate”,则一切正常。我认为这是因为dueDate属性从未更改,而finishedDate属性更改后回读时,类别将有所不同

请帮忙

更新:

以下是我的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];
}
-(NSInteger)节数表视图:(UITableView*)表视图
{
返回[[self.fetchedResultsController节]计数];
}
-(NSInteger)表视图:(UITableView*)表视图行数节:(NSInteger)节
{
id sectionInfo=[[self.fetchedResultsController节]objectAtIndex:section];
返回[sectionInfo numberOfObjects];
}
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
静态NSString*CellIdentifier=@“Cell”;
UITableViewCell*单元格=[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
如果(单元格==nil)
{
cell=[[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault重用标识符:CellIdentifier]自动释放];
}
[self-configureCell:cell-atIndexPath:indexPath];
返回单元;
}
-(NSString*)表格视图:(UITableView*)表格视图标题标题标题部分:(NSInteger)部分
{
id sectionInfo=[[self.fetchedResultsController节]objectAtIndex:section];
返回[sectionInfo name];
}

在我看来,您的问题在于用于提供
sectionNameKeyPath的“category”瞬态属性。
sectionNameKeyPath
的顺序必须与主排序描述符的顺序相同。在您的情况下,这意味着所有“过期”任务的日期必须早于所有“完成”任务的日期必须早于所有“进行中”任务的日期。可以构建这样一个场景,即“完成”任务的
dueDate
位于“正在进行”任务之后或“过期”任务之前。此场景打破了
部分NameKeyPath
的订购要求,并导致
NSFetchedResultsController
抛出
NSInternalConsistencyException

我为您的问题提出了一个解决方案,它不涉及滚动您自己的阵列,然后必须将其拆分为多个部分。在模型中创建一个整数属性,将0映射为“过期”,1映射为“完成”,2映射为“进行中”。将此作为主要排序d
- (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];
}
- (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];
}