好的,这个让我发疯了,我已经尝试了所有可以在互联网上找到的可能的解决方案,但仍然没有。所以这是我的情况:
我有一个 View ,上面有一个按钮。当它被触摸时,它会弹出一个客户列表供用户选择。当他们选择它时,我使用 fetchedresultscontroller 来获取与客户关联的部件并将它们显示在 tableview 中。这一切都很好。问题是如果我选择了客户 A 并插入一个新部件,然后转到客户 B 并插入一个新部件,当我重新选择客户 A 并尝试插入另一个部件时,应用程序崩溃并出现以下错误:
* Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1447.6.4/UITableView.m:976
2011-02-21 10:39:12.896
SalesPro[36203:207] Serious
application error. An exception was
caught from the delegate of
NSFetchedResultsController during a
call to -controllerDidChangeContent:.
Invalid update: invalid number of rows
in section 0. The number of rows
contained in an existing section after
the update (1) must be equal to the
number of rows contained in that
section before the update (1), plus or
minus the number of rows inserted or
deleted from that section (1 inserted,
0 deleted). with userInfo (null)
2011-02-21 10:39:12.907
SalesPro[36203:207] * Terminating
app due to uncaught exception
'NSRangeException', reason:
'-[UITableView
scrollToRowAtIndexPath:atScrollPosition:animated:]:
row (1) beyond bounds (1) for section
(0).'
处理客户选择的代码
-(void) CustomerSelectedRaisedNSNotification *)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"artsList" 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)controllerWillChangeContentNSFetchedResultsController*)controller
{
[[self partsListGrid] beginUpdates];
}
- (void)controllerDidChangeContentNSFetchedResultsController *)controller {
// In the simplest, most efficient, case, reload the table view.
[[self partsListGrid] endUpdates];
}
- (void)controllerNSFetchedResultsController *)controller didChangeObjectid)anObject
atIndexPathNSIndexPath *)indexPath forChangeTypeNSFetchedResultsChangeType)type
newIndexPathNSIndexPath *)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)controllerNSFetchedResultsController *)controller didChangeSectionid <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"artsList" 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];
}
}
这是我必须为我们的下一个版本(很快)解决的最大(最严重)缺陷。我将不胜感激任何帮助!谢谢!
Best Answer-推荐答案 strong>
从修复泄漏的 NSFetchedResultsCONtroller 开始
-(void) CustomerSelectedRaised:(NSNotification *)notif
{
/*...*/
fetchedResultsController = nil;
/*...*/
}
你不应该有多个 NSFetchedResultsControllers 都报告对同一个 tableview 的更改。我认为这就是正在发生的事情。除非 NSFRController 被释放,否则它将向其委托(delegate)报告更改
关于iphone - NSFetchedResultsController 和插入记录的问题,我们在Stack Overflow上找到一个类似的问题:
https://stackoverflow.com/questions/5068511/
|