Core data NSFetchedResultsController';s代表没有';t在谓词更改后触发

Core data NSFetchedResultsController';s代表没有';t在谓词更改后触发,core-data,delegates,nsfetchedresultscontroller,predicate,Core Data,Delegates,Nsfetchedresultscontroller,Predicate,我已经解决这个问题好几个小时了,到目前为止还没有成功。我已经阅读了这里的所有问题,所以这可能与我的问题有关 我有两个实体(A,B),它们通过一对多的关系以树状结构相互连接:A>B 有一个由NSFetchedResultsController支持的UITableViewController,用于显示与实体a的选定对象相关的实体B的所有对象。我正在使用谓词: - (NSFetchedResultsController *)fetchedResultsController { if (_fet

我已经解决这个问题好几个小时了,到目前为止还没有成功。我已经阅读了这里的所有问题,所以这可能与我的问题有关

我有两个实体(A,B),它们通过一对多的关系以树状结构相互连接:A>B

有一个由NSFetchedResultsController支持的UITableViewController,用于显示与实体a的选定对象相关的实体B的所有对象。我正在使用谓词:

    - (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController != nil) {
    return _fetchedResultsController;
}

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"B" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];

[fetchRequest setFetchBatchSize:20];

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"controlDate" ascending:NO];
NSArray *sortDescriptors = @[sortDescriptor];
[fetchRequest setSortDescriptors:sortDescriptors];

NSMutableArray *subpredicates = [NSMutableArray array];
NSPredicate *predicate1 = [NSPredicate predicateWithFormat:@"isRelatedTo = %@", selectedObjectOfA];
[subpredicates addObject:predicate1];
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:@"syncStatus != %d", ObjectDeleted];
[subpredicates addObject:predicate2];

NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:subpredicates];
[fetchRequest setPredicate:predicate];

NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;

NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error]) {
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
}

return _fetchedResultsController;
}
添加、删除和编辑对象时,一切正常。该表将相应地更新。我的类符合NSFetchedResultsControllerDelegate,委托方法是样板文件

但我希望用户能够通过点击“向上”/“向下”按钮循环浏览实体A的所有对象,而无需返回导航堆栈(就像可以直接在邮件应用程序中循环浏览电子邮件一样)。B的关联对象的数量取决于A的选定对象(介于无和之间,比如说20之间)

问题来了: 我的意图是通过更改谓词(不是它的结构或语法,而是只更改'selectedObjectOfA'的值并调用

[self.fetchedResultsController performFetch:&error];
其余的工作应由财务汇报委员会负责

第一个问题是:这种方法正确吗

以下是我已经尝试过的场景:

  • 只需将“selectedObjectOfA”设置为一个新值并调用performFetch就会显示相同的结果(因为我想fetchRequest和谓词不会被更新)

  • 像这样“重置”FRC的请求

    NSMutableArray *subprediactes = [NSMutableArray array];
    NSPredicate *predicate1 = [NSPredicate predicateWithFormat:@"isRelatedTo = %@",    self.selectedObjectOfA];
    [subprediactes addObject:predicate1];
    NSPredicate *predicate2 = [NSPredicate predicateWithFormat:@"syncStatus != %d", ObjectDeleted];
    [subprediactes addObject:predicate2];
    
    NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:subprediactes];
    [self.fetchedResultsController.fetchRequest setPredicate:predicate];
    
更新FRC并返回我认为正确的数据,但应用程序崩溃,行数不正确

'Invalid update: invalid number of rows in section 0.  The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (5), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
因为不会调用NSFetchedResultsController委托方法。因此tableView中的行数不会适应新结果(根据错误消息,返回的对象数是正确的)

第二个问题是:为什么在添加/删除对象时,而不是在谓词(以及结果)发生更改后,委托才会触发

提前谢谢你。

你必须打电话

[tableView reloadData];
修改提取请求后。提取结果控制器仅跟踪
performFetch
之后发生的更改

您可以尝试以下方法来获得表视图的动画更新(但我还没有尝试过,所以我不确定它是否有效):

  • 调用
    [tableView BeginUpdate]
  • 使用
    [tableView deleteRowsAtIndexPaths:…]
    删除所有“旧”行
  • 更新获取的结果控制器获取请求
  • 调用
    [fetchedResultsController performFetch:…]
  • 调用
    [fetchedResultsController FetchedObject]
    的所有对象的
    [tableView InsertRowsAndExpaths:…]
    以插入所有“新”行
  • 调用
    [tableView endUpdates]

要在谓词更改后设置tableview的动画,请执行以下操作:

NSFetchRequest* fetchRequest = self.fetchedResultsController.fetchRequest;
fetchRequest.predicate = newPredicate;

NSArray* objectsBefore = self.fetchedResultsController.fetchedObjects;

[self.fetchedResultsController performFetch:nil];

NSArray* objectsAfter = self.fetchedResultsController.fetchedObjects;


[self.tableView beginUpdates];

if (objectsBefore.count > 0)
{
    for (id objectBefore in objectsBefore)
    {
        if ([objectsAfter indexOfObject:objectBefore] == NSNotFound)
        {
            NSIndexPath* indexPath = [NSIndexPath indexPathForRow:[objectsBefore indexOfObject:objectBefore] inSection:0] ;

            [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationMiddle];
        }
    }
}

if (objectsAfter.count > 0)
{
    for (id objectAfter in objectsAfter)
    {
        if ([objectsBefore indexOfObject:objectAfter] == NSNotFound)
        {
            NSIndexPath* indexPath = [NSIndexPath indexPathForRow:[objectsAfter indexOfObject:objectAfter] inSection:0];

            [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationMiddle];
        }
    }
}

[self.tableView endUpdates];

你说得对。我也试过了,而且效果很好!不幸的是,行动画(添加/删除行)带有
[tableview beginUpdates]
[tableview endUpdates]
在这种情况下丢失了。是否有可能保留它?如果我没记错的话,更改谓词并执行新的获取将重新启动FRC对更改的跟踪,这意味着不可能进行“平滑”转换(因为委托没有被调用)。您能确认吗?@FranzBernt:没有“内置的”方法将FRC fetch请求与动画表视图更新一起更改。-我知道如何实现这一点(请参阅更新的答案),但我不确定这是否有效。@FranzBernt:请告诉我更新方法是否有效。(如果无效,则必须使用
重新加载数据
)。抱歉耽搁了。事实上,这几乎是我在提问之前所做的。唯一的区别是我计算了旧的和新的获取结果之间的行差异,并相应地添加/删除了行。这是可行的。但我觉得这不是“正确的”-步行完成繁重的任务,并保留内置功能或多或少没有使用。因此我的问题。按照你的要求:在没有测试的情况下,我很确定你建议的更新方法会起作用。因此,你会得到选中标记(即使答案不是我希望听到的;)