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

Ios 更新时从UITableView中删除NSFetchedResultsController对象,ios,core-data,uitableview,nsfetchedresultscontroller,Ios,Core Data,Uitableview,Nsfetchedresultscontroller,请温柔一点,这是我的第一篇帖子 当我更新子类NSManagedObject并使用fetched results控制器执行保存时,它不会在“didChangeObject”中调用NSFetchedResultsChangeUpdate,而是调用NSFetchedResultsChangeDelete。保存可以工作并更新对象,但随后会立即将其从UITableView中删除。如果退出并返回,对象会随着更新重新出现在tableview中,这样我就知道它正在将其保存到DB中 我正在使用XCODE 5为一个

请温柔一点,这是我的第一篇帖子

当我更新子类NSManagedObject并使用fetched results控制器执行保存时,它不会在“didChangeObject”中调用NSFetchedResultsChangeUpdate,而是调用NSFetchedResultsChangeDelete。保存可以工作并更新对象,但随后会立即将其从UITableView中删除。如果退出并返回,对象会随着更新重新出现在tableview中,这样我就知道它正在将其保存到DB中

我正在使用XCODE 5为一个简单的任务应用程序开发代码。我使用的是iPhone4S,而不是模拟器来测试它。在我对代码的另一部分做了一些修改之前,它一直工作得很好(我认为没有连接,现在它不工作了)

我有一个排序顺序,当我更新一个对象并按排序顺序更改它时,UtableViewCells的移动有一个很好的动画…现在我必须再次强制提取并执行[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

我有一个rewind(编辑:将reverse更改为rewind after comment)序列,在调用它之前,我设置了将被设置的变量,这些变量存储在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编写代码),我一直在搜索SO,但找不到关于这种行为的任何信息

任何帮助都将不胜感激

编辑:


保存之前,controller.editedObject isDeleted=NO,isupdate=YES,因此我看不出为什么要设置NSFetchedResultsControllerChangeDelete。

我只想讨论一段代码;这可能与所描述的获取结果控制器问题无关

你所谓的“放松/反向”阶段让我感到困惑。我认为
prepareForSegue:sender:
与正式的放松阶段无关。因此,也许你没有真正使用正式的放松阶段(这是通过控制按钮拖动到情节提要场景下的“退出”图标创建的)

除非你指的是一个放松序列,否则没有“反向”序列可以让你回到上一个屏幕。例如,推送序列没有一个单独的称为“弹出”序列的对应序列

我怀疑你在故事板的两个场景之间有交错的分段。换句话说,你创建了一个从场景a到场景B的分段,然后创建了一个从场景B到场景a的分段。如果真是这样,我会避免这样做,因为这是非常规范的。也许会花一些时间来回顾分段


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

看来我对SO的清理不是很好。请参见此处

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

 int index = self.filterSegment.selectedSegmentIndex;
 NSPredicate *predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"filter == %d", index]];
 [fetchRequest setPredicate:predicate];
NSManagedObject子类中的“filter”是一个NSNumber。当我将NSPredicate更改为

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

一切正常。

在NSFetchedResultsChangeDelete案例中添加一个断点,并检查调用堆栈。您可能会看到删除更改来自何处。Matthias-感谢您的评论。不幸的是,我对Xcode不太精通。我设置了一个断点,但不知道如何检查调用堆栈。我将在尽管如此,谢谢你的回答。你是正确的,这是一个放松的阶段,我使用了错误的术语。我从一个so答案中复制了这个,所以假设它是正确的。看起来答案相对简单,请参阅我在matthias建议后找到的答案