好吧,这个让我疯狂,我已经尝试了我可以在互联网上找到的所有可能的解决方案,但仍然没有。所以这是我的情况: 我有一个视图,上面有一个按钮。当触摸它时,它会弹出一个客户列表供用户选择。当他们选择它时,我使用fetchedresultscontroller来获取与客户关联的部件并将其显示在tableview中。这一切都运作良好。问题是如果我选择了客户A并插入新零件,然后转到客户B并插入新零件,当我重新选择客户A并尝试插入另一个零件时,应用程序崩溃时出现以下错误:
*断言失败 - [UITableView _endCellAnimationsWithContext:],/ SourceCache / UIKit_Sim / UIKit-1447.6.4 / UITableView.m:976 2011-02-21 10:39:12.896 SalesPro [36203:207]认真 应用程序错误。一个例外是 抓住了代表 NSFetchedResultsController期间 调用-controllerDidChangeContent:。 无效更新:行数无效 在第0节中。行数 包含在现有部分之后 更新(1)必须等于 包含在其中的行数 更新前的部分(1),加或 减去插入的行数或 从该部分删除(1插入, 0已删除)。用户信息(null) 2011-02-21 10:39:12.907 SalesPro [36203:207] * 终止 应用程序由于未捕获的异常 'NSRangeException',原因: “ - [UITableView的 scrollToRowAtIndexPath:atScrollPosition:动画:]: 第(1)行超出界限(1)的部分 (0)'
处理客户选择的代码
-(void) CustomerSelectedRaised:(NSNotification *)notif
{
NSLog(@"Received Notification - Customer Selected");
selectedCustomer = (Customer *)[notif object];
[self buildCustomerInfoText];
if (popoverController != nil) {
[popoverController dismissPopoverAnimated:YES];
}
fetchedResultsController = nil;
NSError *error;
if (![[self fetchedResultsController] performFetch:&error]) {
//Update to handle error appropriately
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
exit(-1); //fail
}
[self.partsListGrid reloadData];
}
FetchedResultsController代码
#pragma mark -
#pragma mark Fetch results controller
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController != nil) {
return fetchedResultsController;
}
//set-up fetched results controller
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"PartsList" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:20];
NSLog(@"TAMS ID: %@", selectedCustomer.customerTAMSID);
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"customerTAMSID == %@", selectedCustomer.customerTAMSID]];
//set to sort by customer name
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"sortOrder" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:[self managedObjectContext]
sectionNameKeyPath:nil cacheName:nil];
[aFetchedResultsController setDelegate:self];
[self setFetchedResultsController:aFetchedResultsController];
//clean-up
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
//return results
return fetchedResultsController;
}
- (void)controllerWillChangeContent:(NSFetchedResultsController*)controller
{
[[self partsListGrid] beginUpdates];
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
// In the simplest, most efficient, case, reload the table view.
[[self partsListGrid] endUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {
UITableView *tableView = self.partsListGrid;
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 withHeight:tableView.rowHeight];
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.partsListGrid insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.partsListGrid deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeMove:
break;
case NSFetchedResultsChangeUpdate:
break;
default:
break;
}
}
添加零件代码
-(void) addScannedPart:(Part *)part
{
// Check to see if entered part is already in list
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *partsEntity = [NSEntityDescription entityForName:@"PartsList" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:partsEntity];
NSPredicate *predicate = [NSPredicate predicateWithFormat: @"customerTAMSID == %@ AND lineAbbreviation == %@ AND partNumber == %@", selectedCustomer.customerTAMSID, part.lineAbbrev, part.partNumber];
[fetchRequest setPredicate:predicate];
NSError *error = nil;
NSArray *fetchedParts = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
if ([fetchedParts count] == 0) {
//Create a new instance of the entity managed object by the fetched results controller
NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
NSEntityDescription *entity = [[fetchedResultsController fetchRequest] entity];
NSLog(@"Entity Name: %@", [entity name]);
NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
//Add fields to Managed Object
int sortOrder = [[fetchedResultsController fetchedObjects] count];
sortOrder++;
[newManagedObject setValue:[part lineAbbrev] forKey:@"lineAbbreviation"];
[newManagedObject setValue:[part partNumber] forKey:@"partNumber"];
[newManagedObject setValue:[NSNumber numberWithInt:[[part orderQty] intValue]] forKey:@"orderQuantity"];
[newManagedObject setValue:selectedCustomer.customerTAMSID forKey:@"customerTAMSID"];
[newManagedObject setValue:[NSNumber numberWithInt:sortOrder] forKey:@"sortOrder"];
//Save the context
NSError *error = nil;
if (![context save:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
//reload Customer list
NSIndexPath *insertionPath = [fetchedResultsController indexPathForObject:newManagedObject];
[self.partsListGrid selectRowAtIndexPath:insertionPath animated:YES scrollPosition:UITableViewScrollPositionTop];
[self.partsListGrid reloadData];
}
}
这是我在下一个版本中发现的最大(最严重)缺陷(很快就会发现)。我很感激所有的帮助!谢谢!
答案 0 :(得分:2)
首先修复泄漏的NSFetchedResultsCOntroller
-(void) CustomerSelectedRaised:(NSNotification *)notif
{
/*...*/
fetchedResultsController = nil;
/*...*/
}
您不应该有多个NSFetchedResultsControllers都报告对同一个tableview的更改。我认为这就是正在发生的事情。除非取消分配NSFRController,否则它将向其委托报告更改
答案 1 :(得分:1)
好的,感谢这个SO thread,看起来我有它的工作:
我通过CustomerSelectedRaised方法编辑,如下所示:
-(void) CustomerSelectedRaised:(NSNotification *)notif
{
NSLog(@"Received Notification - Customer Selected");
selectedCustomer = (Customer *)[notif object];
[self buildCustomerInfoText];
if (popoverController != nil) {
[popoverController dismissPopoverAnimated:YES];
}
//this is the new code
NSFetchRequest *fetchRequest = [[self fetchedResultsController] fetchRequest];
NSEntityDescription *entity = nil;
entity = [NSEntityDescription entityForName:@"PartsList" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"customerTAMSID == %@", selectedCustomer.customerTAMSID]];
[NSFetchedResultsController deleteCacheWithName:nil];
// end of new code
NSError *error;
if (![[self fetchedResultsController] performFetch:&error]) {
//Update to handle error appropriately
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
exit(-1); //fail
}
[self.partsListGrid reloadData];
}