从核心数据添加新实体后重新加载 UITableView
Reloading UITableView after adding a new entity from core data
目前在通过 UINavigation 添加按钮添加实体时在我的应用程序中重新加载 UITableView 时遇到问题,该按钮会触发视图控制器实现文件中的 addHero 方法。从核心数据的角度来看,添加和删除实体非常有效,因为当应用程序退出并重新启动时,所有实体都正确显示在 table 视图中。当视图栏进行选择时,当视图重新加载进行时,它也可以正常工作。我已尝试重新加载 table 视图,但我不确定我需要按顺序在何处调用此方法。
#pragma mark- NSFetchedResultsControllerDelegate Methods
-(void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
[self.heroTableView beginUpdates];
}
-(void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
[_heroTableView reloadData];
[self.heroTableView endUpdates];
}
-(void)controller:(NSFetchedResultsController *)controller didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
switch (type) {
case NSFetchedResultsChangeInsert:
[self.heroTableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.heroTableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
-(void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath
{
switch (type) {
case NSFetchedResultsChangeInsert:
[self.heroTableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.heroTableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeMove:
case NSFetchedResultsChangeUpdate:
break;
}
}
#pragma mark- UIAlertViewDelegateMethods
-(void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex
{
exit(-1);
}
- (IBAction)addHero:(id)sender {
NSManagedObjectContext *managedObjectContext = [self.fetchedResultsController managedObjectContext];
NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest]entity];
[NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:managedObjectContext];
NSError *error =nil;
BOOL sucess =[managedObjectContext save:&error];
if (!sucess) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:NSLocalizedString(@"Error saving entity", @"Error Saving entity") message:[NSString stringWithFormat:NSLocalizedString(@"Error was: %@, quitting.", @"Error was: %@,quitting." )] delegate:self cancelButtonTitle:NSLocalizedString(@"Aw Nuts", @"Aw Nuts") otherButtonTitles: nil];
[alert show]
}
}
这些行有冲突:
[_heroTableView reloadData];
[self.heroTableView endUpdates];
您要么在 beginUpdates
和 endUpdates
之间更新您的 table,要么放弃动画并直接调用 reloadData
。上面有 unpredictable 结果。
如果您的代理工作正常,它应该在必要的地方插入行,您应该而不是调用reloadData
。从外观上看,您使用的是样板 NSFetchedResultsControllerDelegate
,因此它应该按预期工作。
终于弄明白了。我忘记将获取的结果控制器的委托设置为 tableviewcontroller。但是我最初是在导致问题的 viewDidLoad 方法中这样做的。最好的解决方案是在 getter 方法的实例化点设置 fetchedResultscontoller 的委托。
_fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:sectionKey cacheName:@"Hero"];
_fetchedResultsController.delegate=self;
return _fetchedResultsController;
目前在通过 UINavigation 添加按钮添加实体时在我的应用程序中重新加载 UITableView 时遇到问题,该按钮会触发视图控制器实现文件中的 addHero 方法。从核心数据的角度来看,添加和删除实体非常有效,因为当应用程序退出并重新启动时,所有实体都正确显示在 table 视图中。当视图栏进行选择时,当视图重新加载进行时,它也可以正常工作。我已尝试重新加载 table 视图,但我不确定我需要按顺序在何处调用此方法。
#pragma mark- NSFetchedResultsControllerDelegate Methods
-(void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
[self.heroTableView beginUpdates];
}
-(void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
[_heroTableView reloadData];
[self.heroTableView endUpdates];
}
-(void)controller:(NSFetchedResultsController *)controller didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
switch (type) {
case NSFetchedResultsChangeInsert:
[self.heroTableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.heroTableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
-(void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath
{
switch (type) {
case NSFetchedResultsChangeInsert:
[self.heroTableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.heroTableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeMove:
case NSFetchedResultsChangeUpdate:
break;
}
}
#pragma mark- UIAlertViewDelegateMethods
-(void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex
{
exit(-1);
}
- (IBAction)addHero:(id)sender {
NSManagedObjectContext *managedObjectContext = [self.fetchedResultsController managedObjectContext];
NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest]entity];
[NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:managedObjectContext];
NSError *error =nil;
BOOL sucess =[managedObjectContext save:&error];
if (!sucess) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:NSLocalizedString(@"Error saving entity", @"Error Saving entity") message:[NSString stringWithFormat:NSLocalizedString(@"Error was: %@, quitting.", @"Error was: %@,quitting." )] delegate:self cancelButtonTitle:NSLocalizedString(@"Aw Nuts", @"Aw Nuts") otherButtonTitles: nil];
[alert show]
}
}
这些行有冲突:
[_heroTableView reloadData];
[self.heroTableView endUpdates];
您要么在 beginUpdates
和 endUpdates
之间更新您的 table,要么放弃动画并直接调用 reloadData
。上面有 unpredictable 结果。
如果您的代理工作正常,它应该在必要的地方插入行,您应该而不是调用reloadData
。从外观上看,您使用的是样板 NSFetchedResultsControllerDelegate
,因此它应该按预期工作。
终于弄明白了。我忘记将获取的结果控制器的委托设置为 tableviewcontroller。但是我最初是在导致问题的 viewDidLoad 方法中这样做的。最好的解决方案是在 getter 方法的实例化点设置 fetchedResultscontoller 的委托。
_fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:sectionKey cacheName:@"Hero"];
_fetchedResultsController.delegate=self;
return _fetchedResultsController;