我有一個與dueDate屬性的託管對象。除了使用一些醜陋的日期字符串作爲我的UITableView的節頭我創建了一個名爲「類別」一過性屬性,顯示的定義它像這樣:自定義部分名稱崩潰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"];
表格最初顯示正常,顯示其dueDate未在標題爲「正在進行」的部分中傳遞的未完成項目。現在,用戶可以點擊表格視圖中的一行,將新的詳細信息視圖推送到導航堆棧上。在這個新視圖中,用戶可以點擊一個按鈕來指示該項目現在是「完成」。下面是該按鈕的處理程序(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被調用。
在這一點上,我卡住了。如果我將我的sectionNameKeyPath更改爲「dueDate」,那麼一切正常。我認爲這是因爲dueDate屬性永遠不會改變,而在finishedDate屬性更改後回讀時類別會有所不同。
請幫忙!
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];
}
我很尊重馬庫斯 - 我不認爲這是一個錯誤。 NSFetchedResultsController的文檔聲明:「獲取請求必須至少有一個排序描述符,如果控制器生成段,數組中的第一個排序描述符用於將對象分組爲段;它的鍵必須與sectionNameKeyPath相同或使用其鍵的相對順序必須與使用sectionNameKeyPath的順序相匹配。「正如我所看到的,發生崩潰的原因是排序描述符的鍵和sectionNameKeyPath的鍵具有不同的排序順序。 – glorifiedHacker 2010-03-27 20:00:06
非常有趣的建議。基於我從SDK文檔中讀取的內容具有意義。我已經走過了一個單獨陣列的路線,但我會看看我是否可以在某個時候嘗試一下。謝謝! – 2010-04-04 07:03:41