我有一个简单的表视图,包含1个部分和2个行。我使用NSFetchedResultsController
来保持表与CoreData同步。我对CD中的一行进行了更改,触发了一个要更新和移动的表视图单元格。问题是,在cellForRowAtIndexPath:
期间调用NSFetchedResultsChangeUpdate
时,会返回错误的单元格(这有意义b / c尚未移动单元格)。因此,使用新更新的数据更新了错误的单元格。之后处理NSFetchedResultsChangeMove
消息,以便单元格交换位置(单元格的内容都不会更新,因为它只是一个移动调用)。结果是两个单元都反映了来自新更新的CD实体的数据。重新加载表可以解决问题。我正在运行iOS 6。
换句话说,如果索引0处的单元格表示实体A,索引1表示实体B,并且我将实体A更新为A',使得2个单元格反向排序,结果是我看到0:A'1:A当我期待0:B,1:A'。
- (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:
//the wrong cell is updated here
[self configureCell:(SyncCell*)[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableView moveRowAtIndexPath:indexPath toIndexPath:newIndexPath];
//this code produces errors too
//[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
//[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
答案 0 :(得分:6)
解决方案是:
[self configureCell:(SyncCell*)[tableView cellForRowAtIndexPath:indexPath] atIndexPath:newIndexPath ? newIndexPath : indexPath];
在更新期间提供新索引路径。然后使用delete和insert而不是move。我还是想知道是否有其他人有任何意见。
答案 1 :(得分:4)
我建议你看一下这个blogpost
修复错误很容易。只需依赖我上面描述的UITableView的行为,并使用reloadRowsAtIndexPaths:withRowAnimation:方法替换对configureCell:atIndexPath:的调用,这将自动做正确的事情:
case NSFetchedResultsChangeUpdate:
[tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
break;
答案 2 :(得分:3)
调用configureCell时,根据传入的对象查找indexPath。此时indexPath和newIndexPath都不可靠。例如:
case NSFetchedResultsChangeUpdate:
myPath = [controller indexPathForObject:anObject];
if (myPath) {
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:myPath];
}
break;
答案 3 :(得分:1)
唯一对我有用的解决方案:Thomas Worrall's Blog: Reordering rows in a UITableView with Core Data
首先,必须在NSManagedObject中创建一个属性来挂起对象的最后一个顺序。
@interface MyEntity : NSManagedObject
@property (nonatomic, retain) NSNumber * lastOrder;
@end
然后,在ViewController.m中声明一个属性:
@interface ViewController ()
@property (nonatomic) BOOL isReordering;
@end
在方法 tableView:moveRowAtIndexPath:toIndexPath:中,管理临时数组中的更改:
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
_isReordering = YES;
NSMutableArray *arrayNewOrder = [[_fetchedResultsController fetchedObjects] mutableCopy];
MyEntity *myManagedObject = [arrayNewOrder objectAtIndex:fromIndexPath.row];
[arrayNewOrder removeObjectAtIndex:fromIndexPath.row];
[arrayNewOrder insertObject:myManagedObject atIndex:toIndexPath.row];
for (int i=0; i < [arrayNewOrder count]; i++)
{
myManagedObject = [arrayNewOrder objectAtIndex:i];
myManagedObject.lastOrder = [NSNumber numberWithInt:i];
}
_isReordering = NO;
NSError *error;
BOOL success = [self.fetchController performFetch:&error];
if (!success)
{
// Handle error
}
success = [[self managedObjectContext] save:&error];
if (!success)
{
// Handle error
}
}
Thomas解释了执行获取和保存上下文:
我不完全确定为什么需要首先执行提取,但是 当我这样做时,它修复了大量的疯狂错误!
最后一个技巧是处理NSFetchedResultsController委托方法 controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:,特别是在 NSFetchedResultsChangeMove:
case NSFetchedResultsChangeMove:
{
if (!_isReordering)
{
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
}
break;
}
它对我有用!我希望它可以帮到你!