[注意,代码格式的道歉因复制和粘贴而变得奇怪!] 您好,
我有一个tableview,它从核心数据中获取数据,并使用排序规则将数据写入表中以索引表。代码略微修改了Apple CoreDataBooks
的代码一切正常,除非将新数据输入核心数据,然后我收到一条错误消息,说明下面的消息。我已经看到其他一些网站出现此错误,但无法解决问题,与有0行的部分有关,直到输入新数据我相信
ConnectU [6168:207]严重的应用程序错误。在调用-controllerDidChangeContent:期间,从NSFetchedResultsController的委托中捕获到异常。 * - [NSMutableArray objectAtIndex:]:索引0超出带有userInfo的空数组的边界(null)
代码在
之下@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];
}
答案 0 :(得分:0)
您不应该混合使用UILocalizedIndexedCollation和NSFetchedResultsController。使用其中一种。
排序规则从表视图中获取索引,就像它第一次创建时一样。当FRC添加新行时,排序规则的索引将变为无效,从而产生错误。
如果您正在使用FRC,则无需进行整理,因为FRC也会为您管理部分,并使数据更改能够正确更新。
答案 1 :(得分:0)
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[self configureSections];
[self.tableView reloadData];
}
在configureSections中,我从获取的控制器中获取数据到friendDataArray,然后重新加载表。作品:))