2011-03-25 52 views
0

[注,換碼格式的道歉已經怪異的複製和粘貼!] 嗨,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]; 
} 

回答

0

你不應該混合UILocalizedIndexedCollat​​ion和NSFetchedResultsController 。使用一個或另一個。

排序規則從tableview中獲取它的索引,就像它在第一次創建時一樣。當FRC添加新行時,排序規則的索引變爲無效,從而產生錯誤。

如果您使用的是FRC,則不需要排序規則,因爲FRC也爲您管理各個部分,並且可以使它們正確更新數據更改。

0

Yer我注意到我做錯了。我除去NRC功能和用下面的代碼

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

的configureSections內,我從取出控制器插入friendDataArray獲取數據,然後重新加載該表。作品:)