从表视图中删除已正确删除的NSManagedObject,然后在保存时重新显示

时间:2012-08-10 22:49:16

标签: objective-c ios core-data nsfetchedresultscontroller nsmanagedobjectcontext

我正在使用NSFetchedResultsController和NSFetchedResultsControllerDelegate来驱动UITableViewController / UITableView。单击按钮会触发通过[managedObjectContext deleteObject:aManagedObject]删除NSManagedObject。

NSFetchedResultsControllerDelegate方法正确触发,并从UITableView中删除该行。

这是事情变得奇怪的地方。当我调用[managedObjectContext save:&error]时,使用已删除的NSManagedObject作为对象调用NSFetchedResultsControllerDelegate方法controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:(并且在托管对象上isDeleted为YES),更改类型为NSFetchedResultsChangeInsert,它将已删除的NSManagedObject添加回UITableView

我试图通过检查委托方法中的isDeleted标志来抑制插入,但这会导致beginUpdatesendUpdates断言失败。

我做错了什么或出了故障?我错过了某个地方的一步吗?

3 个答案:

答案 0 :(得分:0)

你有没有忘记下面的代码?

如果您仍然感到困惑,Apple的示例代码,请参阅。对你有很大的帮助。

iPhoneCoreDataRecipes

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *cellIdentifier = @"cellIdentifier";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    }

    [self configureCell:cell atIndexPath:indexPath];

    return cell;
}

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    // Configure the cell
    MyObject *recipe = (MyObject *)[fetchedResultsController objectAtIndexPath:indexPath];
    //do stuff
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
        UITableView *tableView = self.tableView;

        switch(type) {
            case NSFetchedResultsChangeInsert:
                break;

            case NSFetchedResultsChangeDelete:
                [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
                break;

            case NSFetchedResultsChangeUpdate:
                [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
                break;

            case NSFetchedResultsChangeMove:
                [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
                [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
                break;
        }
    }

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
        switch(type) {
            case NSFetchedResultsChangeInsert:
                [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
                break;

            case NSFetchedResultsChangeDelete:
                [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
                break;
        }
    }

答案 1 :(得分:0)

我暂时找到了解决办法:

[managedObjectContext deleteObject:managedObject];
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    [managedObjectContext performBlock:^{
        resultsController.delegate = nil;
        [managedObjectContext save:nil];
        resultsController.delegate = self;
    }];
});

这将删除对象,让NSFetchedResultsController委托fire从UITableView中删除该行。然后,稍后发送的调度将断开委托,执行保存然后重新挂起代理。

答案 2 :(得分:0)

面对与您完全相同的问题,我可以意识到,只有一个对另一个对象或上下文删除的对象的引用会使其保持活动状态为错误,直到删除引用为止。如果应用程序尝试再次访问该已删除的对象,它将崩溃。单个引用可能是删除对象重新出现的原因。

在我的情况下,在调用异步删除操作之前,释放对象的UIViewController实例引用将修复此问题。

// Delete a NSManagedObject.
NSManagedObjectID *objectID = [[managedObject objectID] copy];
// Release all references to the object.
self.managedObject = Nil;
// Asynchronously delete the object.
[self asynchronouslyDeleteManagedObjectWithManagedObjectID:objectID];

忽略Release all references to the object部分会使对象在被删除到isDeleted观察者实例后重新显示为NSFetchedResultsController