NSFetchedResultsController和用户驱动的更改:最佳方法?

时间:2014-01-22 21:01:52

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

仍然在努力解决这个问题。我正在读取coredata中的数据,并使用NSFetchedResultsController将其呈现在表视图中。问题是,我希望我的用户能够一次编辑所有内容:重新排序,重命名行中的文本字段,删除行并添加新行。

到目前为止,我(几乎!)在用户驱动的更改发生后立即使用转义所有NSFetchedResultsController委托方法顺利工作: 即:

- (void)controller:(NSFetchedResultsController *)controller
   didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath *)indexPath
     forChangeType:(NSFetchedResultsChangeType)type
      newIndexPath:(NSIndexPath *)newIndexPath
{
    if (self.suspendAutomaticTrackingOfChangesInManagedObjectContext) return;

只要在我的表视图中启动编辑模式,我就将此属性设置为YES。重新排序后,我重新获取整个获取请求并重新加载表。我只停止挂起并在添加或删除项目时将此属性设置为NO:

- (void)tableView:(UITableView *)aTableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Update the data model according to edit actions delete or insert.
    if (editingStyle == UITableViewCellEditingStyleDelete) {

        //Basically saves the textfield
        if (self.activeField && [self.activeField isFirstResponder]){
            [self.activeField resignFirstResponder];
        }
        self.suspendAutomaticTrackingOfChangesInManagedObjectContext = NO;
        [self.managedObjectContext deleteObject:[self.fetchedResultsController objectAtIndexPath:indexPath]];

        //Results in a strange delete button behaviour. If omitted the order should still be valid.
//        //Adjust the indices of the remaining entries
//        int i = 1;
//        for (MainCategory *fetchedResult in [self.fetchedResultsController fetchedObjects])
//        {
//            fetchedResult.position = [NSNumber numberWithInt:i++];
//        }
    }
}

在我的文本字段中我做了结束编辑方法:

-(void)textFieldDidEndEditing:(UITextField *)textField
{
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:textField.tag inSection:0];
    MainCategory *mainCategory = [self.fetchedResultsController objectAtIndexPath:indexPath];

    if(textField.text != mainCategory.name){
        mainCategory.name = textField.text;
    }

    self.activeField = nil;
}

现在你可以看到我目前唯一的问题了:如果我在说第3行的文本字段,我将删除第2行,有时(并非总是!)删除之前的行号4现在排第3行,获取我之前编辑的文本字段的文本。我想这是因为我使用IndexPath设置了主类别名称。可能NSFetchedResultsController在那里搞砸了......

知道为什么或我能做什么?我想完全避免使用NSFetchedResultsController委托并且只是一直在重新发送一些更改。但这应该和我现在的结果基本相同而且不是真的更快......所以我应该怎么做?

编辑: FRC委托方法

#pragma mark - NSFetchedResultsControllerDelegate
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
    if (self.suspendAutomaticTrackingOfChangesInManagedObjectContext) return;

    [self.tableView beginUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller
  didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
           atIndex:(NSUInteger)sectionIndex
     forChangeType:(NSFetchedResultsChangeType)type
{
    if (self.suspendAutomaticTrackingOfChangesInManagedObjectContext) return;

    switch(type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;

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


- (void)controller:(NSFetchedResultsController *)controller
   didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath *)indexPath
     forChangeType:(NSFetchedResultsChangeType)type
      newIndexPath:(NSIndexPath *)newIndexPath
{
    if (self.suspendAutomaticTrackingOfChangesInManagedObjectContext) return;

    switch(type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

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

        case NSFetchedResultsChangeUpdate:
            [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

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

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
    if(self.suspendAutomaticTrackingOfChangesInManagedObjectContext) return;

    [self.tableView endUpdates];
}

- (void)endSuspensionOfUpdatesDueToContextChanges
{
    _suspendAutomaticTrackingOfChangesInManagedObjectContext = NO;
}

- (void)setSuspendAutomaticTrackingOfChangesInManagedObjectContext:(BOOL)suspend
{
    if (suspend) {
        _suspendAutomaticTrackingOfChangesInManagedObjectContext = YES;
    } else {
        [self performSelector:@selector(endSuspensionOfUpdatesDueToContextChanges) withObject:0 afterDelay:0];
    }
}

1 个答案:

答案 0 :(得分:0)

FRC仍然在滚动时为您提供批量加载,因此即使您滥用委托功能,仍然值得保留它。

您的问题实际上是在编辑完成时使用标记。实际上你应该在编辑开始时记录行索引。如果您在编辑后没有更新整个表格,则需要小心使用字段标记,因为您可能有多个重复的标记和错误的标记。

解决方案是自定义单元格,其中单元格是字段的委托。编辑时,该字段通知单元格,单元格通知控制器。然后,您可以从表格视图中实际从单元格和索引中获取信息。