[注,換碼格式的道歉已經怪異的複製和粘貼!] 嗨,ContentDidChange上的UITableView有節
我有一個實現代碼如下後者從核心數據的數據,並將數據寫入到表使用排序規則爲表格編制索引。該代碼稍作修改,從Apple CoreDataBooks
這一切都工作正常,除非新數據輸入到核心數據,然後我收到一條錯誤消息,說下面的消息。我已經看到了一些其他網站有這個錯誤,但直到進入新的數據可以不精的解決方案,是與具有0行的部分,我相信
ConnectU的[6168:207]嚴重的程序錯誤。在調用-controllerDidChangeContent:期間,NSFetchedResultsController的委託捕獲到異常。 * - [NSMutableArray的objectAtIndex:]:索引0超出界限爲空數組與USERINFO(空)
的代碼是下面
@synthesize managedObjectContext=__managedObjectContext;
@synthesize fetchedResultsController;
@synthesize delegate;
@synthesize filteredListContent;
@synthesize savedSearchTerm;
@synthesize savedScopeButtonIndex;
@synthesize searchIsActive;
@synthesize friendDataArray, sectionsArray, collation;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
__managedObjectContext = [(ConnectUAppDelegate*)[UIApplication sharedApplication].delegate managedObjectContext];
self.title = @"Friends";
UITabBarItem *item = [[UITabBarItem alloc] initWithTabBarSystemItem:UITabBarSystemItemContacts tag:0];
self.tabBarItem = item;
[item release];
NSError *error;
if (![[self fetchedResultsController] performFetch:&error]) {
// Update to handle the error appropriately.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
exit(-1); // Fail
}
}
return self;
}
- (void)updateFeed:(id)sender {
// Add some new data to the core data and save, no problems
[self.tableView reloadData];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Set the table view's row height
self.tableView.rowHeight = 44.0;
//Add the refresh button
UIBarButtonItem* refreshButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(updateFeed:)];
[self.navigationItem setLeftBarButtonItem:refreshButton animated:YES];
[refreshButton release];
// ******** Search Bar Set Up ******** //
// hidden to reduce code here
// ******** Search Bar Set Up Complete ******** //
// Get the friends data
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:@"Friends" inManagedObjectContext:[self managedObjectContext]]];
NSError *error2 = nil;
NSArray *fetchResults2 = [[self managedObjectContext] executeFetchRequest:request error:&error2];
if (fetchResults2) {
friendDataArray = [NSMutableArray arrayWithArray:fetchResults2];
}
[self configureSections];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if (self.searchIsActive) {
return 1;
}
// The number of sections is the same as the number of titles in the collation.
return [[collation sectionTitles] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// If a search is taking place, return number of items in filteredListContent
if (self.searchIsActive) {
return [self.filteredListContent count];
}
// The number of time zones in the section is the count of the array associated with the section in the sections array.
NSArray *timeZonesInSection = [sectionsArray objectAtIndex:section];
return [timeZonesInSection count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSArray *friendsInSection = [sectionsArray objectAtIndex:section];
if([friendsInSection count] != 0) {
return [[collation sectionTitles] objectAtIndex:section];
}
return @"";
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return [collation sectionIndexTitles];
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
return [collation sectionForSectionIndexTitleAtIndex:index];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Friends_View";
// Create a cell, reuse a useable cell if available
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
// If search is taking place, then get cell contents from the filteredlistcontent
if (self.searchIsActive) {
Friends *friend = [[self filteredListContent] objectAtIndex:[indexPath row]];
NSString *name = [[NSString alloc] initWithFormat:@"%@ %@", [friend valueForKeyPath:@"first_name"] ,[friend valueForKeyPath:@"last_name"]];
cell.textLabel.text = name;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
// No search taking place so therefore get data from sectionsArray
} else {
// Get the time zone from the array associated with the section index in the sections array.
NSArray *friendsInSection = [sectionsArray objectAtIndex:indexPath.section];
// Configure the cell with the time zone's name.
Friends *friend = [friendsInSection objectAtIndex:indexPath.row];
NSString *name = [[NSString alloc] initWithFormat:@"%@ %@", [friend valueForKeyPath:@"first_name"] ,[friend valueForKeyPath:@"last_name"]];
cell.textLabel.text = name;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Friends *friend;
// If search is taking place, get object from filteredListContent
if (self.searchIsActive) {
friend = [[self filteredListContent] objectAtIndex:[indexPath row]];
// Else get a normal friend object
} else {
NSArray *friendsInSection = [sectionsArray objectAtIndex:indexPath.section];
friend = [friendsInSection objectAtIndex:indexPath.row];
}
// Create a friendDetail View controller and push this into the view
FriendsDetail_ViewController *friendsDetail = [[FriendsDetail_ViewController alloc] initWithStyle:UITableViewStyleGrouped];
NSString *name = [[NSString alloc] initWithFormat:@"%@ %@", [friend valueForKeyPath:@"first_name"] ,[friend valueForKeyPath:@"last_name"]];
friendsDetail.title = name;
friendsDetail.friend_data = friend;
[friendsDetail setDelegate:self];
[self.navigationController pushViewController:friendsDetail animated:YES];
[friendsDetail release];
}
- (void)configureSections {
// Get the current collation and keep a reference to it.
self.collation = [UILocalizedIndexedCollation currentCollation];
NSInteger index, sectionTitlesCount = [[collation sectionTitles] count];
NSMutableArray *newSectionsArray = [[NSMutableArray alloc] initWithCapacity:sectionTitlesCount];
// Set up the sections array: elements are mutable arrays that will contain the time zones for that section.
for (index = 0; index < sectionTitlesCount; index++) {
NSMutableArray *array = [[NSMutableArray alloc] init];
[newSectionsArray addObject:array];
[array release];
}
// Segregate the time zones into the appropriate arrays.
for (Friends *friend in friendDataArray) {
// Ask the collation which section number the time zone belongs in, based on its locale name.
NSInteger sectionNumber = [collation sectionForObject:friend collationStringSelector:@selector(first_name)];
// Get the array for the section.
NSMutableArray *sectionTimeZones = [newSectionsArray objectAtIndex:sectionNumber];
// Add the time zone to the section.
[sectionTimeZones addObject:friend];
}
// Now that all the data's in place, each section array needs to be sorted.
for (index = 0; index < sectionTitlesCount; index++) {
NSMutableArray *timeZonesArrayForSection = [newSectionsArray objectAtIndex:index];
// If the table view or its contents were editable, you would make a mutable copy here.
NSArray *sortedTimeZonesArrayForSection = [collation sortedArrayFromArray:timeZonesArrayForSection collationStringSelector:@selector(first_name)];
// Replace the existing array with the sorted array.
[newSectionsArray replaceObjectAtIndex:index withObject:sortedTimeZonesArrayForSection];
}
self.sectionsArray = newSectionsArray;
[newSectionsArray release];
}
- (NSFetchedResultsController *)fetchedResultsController {
// Set up the fetched results controller if needed.
if (fetchedResultsController == nil) {
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Friends" inManagedObjectContext:[self managedObjectContext]];
[fetchRequest setEntity:entity];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"first_name" ascending:YES selector:nil];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
// Recover query
[fetchRequest setSortDescriptors:sortDescriptors];
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[self managedObjectContext] sectionNameKeyPath:nil cacheName:@"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
}
return fetchedResultsController;
}
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
// The fetch controller is about to start sending change notifications, so prepare the table view for updates.
[self.tableView beginUpdates];
}
- (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:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
//[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] 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 {
// The fetch controller has sent all current change notifications, so tell the table view to process all updates.
[self.tableView endUpdates];
}