5

I've got a NSPredicate on my FRC's fetchRequest. At some point an object is added to CoreData, I create a new predicate, update the fetchRequest and perform a fetch:

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

This does however not invoke the FRC's delegate methods like controllerWillChangeContent:. And my table view is not updated.

However, when I add the following line:

[self.tableView reloadData];

below the two shown above, I do see the expected update. This shows that the data to be displayed has indeed changed.

I've checked the new predicate and it's fine. I also set FRC's delegate to self, and its methods are invoked in other cases.

Any ideas already what could be wrong?

meaning-matters
  • 21,929
  • 10
  • 82
  • 142

3 Answers3

4

The behaviour you have described is expected. According to the Apple documentation, if you want to modify a fetch request on a NSFetchedResultsController, you must delete the cache (if you are using one), modify the NSFetchRequest, then invoke performFetch: (which won't call any of the delegate methods).

If you want to know what has changed between the predicates, you need to store the old state and compare. A library that I've used in the past for this is Doppelganger.

stu
  • 461
  • 4
  • 6
  • I did consult this documentation, but I did not readily found it saying that the delegate methods were not called. Where can I find that? On the contrary I read: 'Memory-only tracking: ... updates section and ordering information ...'. – meaning-matters Jan 11 '16 at 06:32
  • See the section "Modifying the Fetch Request" in https://developer.apple.com/library/ios/documentation/CoreData/Reference/NSFetchedResultsController_Class/#//apple_ref/doc/uid/TP40008227-CH1-SW23 – Avi Jan 11 '16 at 07:22
0

The delegate methods are called when the FRC observes changes to the set of fetched objects it has eyes on after you do a fetch. If you go and change the predicate and do a new fetch, the FRC is reset and is now observing a different set of objects. The delegate methods aren't called because nothing changed in the original set of objects.

Zoë Smith
  • 1,084
  • 1
  • 11
  • 19
0

Careful if you are literally changing the entity...

We had a tricky one, not only the sort changed but the actual entity class changed, so for two different tab buttons,

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

but then ..

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

In fact if you're doing that, THIS will NOT work:

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
}

It will eventually crash.

It seems you need this:

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
}

That (seems to) reliably work.

Community
  • 1
  • 1
Fattie
  • 27,874
  • 70
  • 431
  • 719