更改 NSFetchedResultsController 的 fetchRequest.predicate 不会触发委托

Changing NSFetchedResultsController's fetchRequest.predicate does not trigger delegate

我的 FRC fetchRequest 上有一个 NSPredicate。在某个时候,一个对象被添加到 CoreData,我创建了一个新的谓词,更新 fetchRequest 并执行提取:

self.fetchedAddressesController.fetchRequest.predicate = self.predicate;
BOOL success = [self.fetchedAddressesController performFetch:nil];

然而,这不会像 controllerWillChangeContent: 那样调用 FRC 的委托方法。我的 table 视图没有更新。

但是,当我添加以下行时:

[self.tableView reloadData];

在上面显示的两个下方,我确实看到了预期的更新。这说明要显示的数据确实发生了变化

我检查了新谓词,没问题。我也将FRC的delegate设置为self,其他情况下会调用它的方法

有什么想法是错误的吗?

您描述的行为是正常的。根据 Apple documentation,如果你想修改 NSFetchedResultsController 上的获取请求,你必须删除缓存(如果你正在使用缓存),修改 NSFetchRequest,然后调用 performFetch:(它不会调用任何委托方法)。

如果你想知道谓词之间发生了什么变化,你需要存储旧状态并进行比较。我过去为此使用的库是 Doppelganger.

当 FRC 在您执行提取后观察到它所关注的已提取对象集发生变化时,将调用委托方法。如果您去更改谓词并执行新的获取,则 FRC 将重置并且现在正在观察一组不同的对象。委托方法没有被调用,因为原始对象集中没有任何变化。

如果您真的要更改实体,请小心...

我们遇到了一个棘手的问题,不仅更改了排序,而且更改了实际实体 class,因此对于两个不同的选项卡按钮,

let r = NSFetchRequest<NSFetchRequestResult>(entityName: "CD_Cats")

但是然后..

let r = NSFetchRequest<NSFetchRequestResult>(entityName: "CD_Dogs")

事实上,如果你这样做,这将行不通:

func buttonLeft() {
    mode = .cats
    bringupFetchRequest()
    pull.feedForCats() // get fresh info if any at the endpoints
}

func buttonRight() {
    mode = .dogs
    bringupFetchRequest()
    pull.feedForDogs() // get fresh info if any at the endpoints
}

它最终会崩溃。

看来你需要这个:

func buttonLeft() {
    mode = .cats
    bringupFetchRequest()
    tableView.reloadData()
    pull.feedForCats() // get fresh info if any at the endpoints
}

func buttonRight() {
    mode = .dogs
    bringupFetchRequest()
    tableView.reloadData()
    pull.feedForDogs() // get fresh info if any at the endpoints
}

那(似乎)可靠地工作。