NSFetchedResultsController对象在更新时从UITableView中删除

时间:2014-03-31 20:43:58

标签: ios core-data uitableview nsfetchedresultscontroller

请保持温和,这是我的第一篇文章。

当我更新子类NSManagedObject并使用获取的结果控制器执行保存时,不是在“didChangeObject”中调用NSFetchedResultsChangeUpdate,而是调用NSFetchedResultsChangeDelete。保存工作并更新对象,但随后立即从UITableView中删除它。如果我退出并返回,该对象会在更新后出现在tableview中,因此我知道它会将其保存到数据库中。

我正在使用XCODE 5为一个简单的任务应用程序开发代码。我使用的是iPhone 4S而不是模拟器来测试它。它工作正常,直到我对代码的另一部分做了一些mod(我认为没有连接,现在它不起作用。

我有一个排序顺序,当我更新一个对象并且它按排序顺序改变时,有一个很好的动画可以移动UITableViewCells ....现在我必须强制再次获取并执行[self。 tableView reloadData]。这是一个黑客,因为我没有得到任何动画,但这是我可以让它更新的唯一方法:

我准备了segue方法:

- (void) prepareForSegue: (UIStoryboardSegue *) segue sender: (id) sender
{
// configure the destination view controller:
if ( [segue.destinationViewController isKindOfClass: [ShowEditTaskTableViewController class]])
{

    if ([sender isKindOfClass:[UITableViewCell class]] )
    {


        NSIndexPath *indexPath = [self.taskTableView indexPathForCell:sender];
        [self.taskTableView deselectRowAtIndexPath:indexPath animated:YES];

        // Pass the selected task to the new view controller.
        ShowEditTaskTableViewController *detailViewController = segue.destinationViewController;

        Task *info = [self.fetchedResultsController objectAtIndexPath:indexPath];
        detailViewController.editedObject = info;
    }
    else
    {

        NSIndexPath *indexPath = [self.taskTableView indexPathForCell:sender];
        [self.taskTableView deselectRowAtIndexPath:indexPath animated:YES];
        ShowEditTaskTableViewController *detailViewController =           segue.destinationViewController;

        Task *info = (Task *)[NSEntityDescription insertNewObjectForEntityForName:@"Task" inManagedObjectContext:self.managedObjectContext];
        detailViewController.editedObject = info;




    }

}

}

这里没什么特别的。 “任务”是我的NSManagedObject。

我有一个倒带(编辑:在评论后改为反向倒带)segue,在调用之前,我设置了将被设置的变量存储在editedObject中。:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{

if ([segue.identifier isEqualToString:@"addNewTaskSave"]) {
    // Note: This is an unwind segue to go back to the previous screen.

    self.dueDate = self.taskDatePicker.date;
    self.description = self.taskDescriptionTextView.text;
    self.priority = self.taskPrioritySegment.selectedSegmentIndex;
    }
}

并在RootViewController中调用:

- (IBAction)addNewTaskSave:(UIStoryboardSegue *)segue
{

ShowEditTaskTableViewController *controller = segue.sourceViewController;

controller.editedObject.shortDesc = controller.description;
controller.editedObject.priority = @(controller.priority);

controller.editedObject.dueDate = controller.dueDate;
controller.editedObject.completed = @0;

NSError *error;
if (![self.managedObjectContext save:&error]) {
    ...
}

.....     }

它使用标准的didChangeObject委托方法。这很好用,直到我明显改变了一些东西。

现在保存后,它会设置NSFetchedResultsChangeDelete选项并删除表格行。

修复是添加:

self.fetchedResultsController = nil;

if (![[self fetchedResultsController] performFetch:&error]) {
   ...
}
[self.taskTableView reloadData];

然而,这意味着实际观察到的只是表视图的直接更新,没有动画。

如果没有此代码,您可以观察到表格行的动画删除。如果我退出并重新启动,我编辑的对象就在那里。

我已经搜索了过去4周(我编写IOS的时间)一直是我不变的伴侣,并且找不到任何关于此行为的信息。

非常感谢任何帮助。

编辑:

在保存之前

,controller.editedObject isDeleted = NO,isUpdated = YES,所以我看不出它为什么设置NSFetchedResultsControllerChangeDelete。

2 个答案:

答案 0 :(得分:1)

我要讨论你的一段代码;这可能与所描述的获取结果控制器问题有关。

你所谓的放松/逆转让我感到难过。我不认为prepareForSegue:sender:与正式解雇相关。所以也许你并没有真正使用官方展开segue(通过控制 - 从按钮拖动到#34;退出"故事板场景下面的图标)创建。

除非你指的是一个放松信号,否则就没有"反向" segue将您带回到之前的屏幕。例如,推送segue没有一个单独的对应物,称为" pop" Segue公司。

我怀疑你在故事板中的两个场景之间有交错。换句话说,你创建了一个从场景A到场景B的segue,你创建了一个从场景B到场景A的segue。如果真的如此,我会避免这样做,因为它是非常规的。也许花点时间回顾一下segues。

好的,我将简要介绍获取的结果控制器问题。如果在由提取的结果控制器填充的表视图中存在用户驱动的数据更改,则需要设置一个标志并暂时"关闭"获取的结果控制器委托方法。在"用户驱动的更新"下的NSFetchedResultsControllerDelegate协议的文档中简要提到了此问题。

答案 1 :(得分:0)

看来我的SO搜索并不是很好。见https://stackoverflow.com/a/18998335/3482632

我添加了一个UISegmentControl来过滤并使用其段索引的int值。

 int index = self.filterSegment.selectedSegmentIndex;
 NSPredicate *predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"filter == %d", index]];
 [fetchRequest setPredicate:predicate];

"过滤器"在我的NSManagedObject子类中是一个NSNumber。当我将NSPredicate更改为

 NSPredicate *predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"filter == %@", @(index)]];

一切正常。