Just one NSFetchedResultsController, thanks.

I try not to optimize before profiling, and most times I succeed. This was not one of those times.

I’m at the point in this app where the basics are in place, and now it’s time to add the more complicated bits. I know where I want the app to end up, functionality-wise, so I started thinking about how I’d implement that, then backtracking to see if the current setup could work the same way. Figured it’d save me some headache in the long run.

The simple explanation is I’ve got a list of items, split into categories. An item’s category is optional, and I’d prefer those in the nil category sort to the bottom of things. (I did think about using an NSComparator-based NSSortDescriptor to handle that, but this other way seemed better at the time.) My solution, since it seemed to jive well with how things would need to be later on, was to use two NSFetchedResultsControllers to populate my UITableView.

Borrowing the old phrase – “Now I have two problems.”

At first blush, this works a treat. Check for (section == [[nonNilController sections] count]) to known if you’re dealing with the nil section, and respond accordingly. A little bit of extra code in the NSFetchedResultsControllerDelegate callbacks to adjust the sections/indexPaths to take this into account, but nothing heinous. And then you start moving items between sections, and it all falls apart.

Say you’ve got two sections: a normal category followed by your special nil one. There are a few items in the first category, and one in nil. You edit the one nil row, and move it to the existing category. The resulting FRC and tableView delegate callbacks look something like this:

  • Non-nil FRC – insert row at [0, 0]
  • Get TV section count – it’s 2
  • Get TV row count for section 0 (actual category) – (original count plus one for the new row)
  • Get TV row count for section 1 (nil category) – 1
  • Nil FRC – delete row at [1, 0]
  • Get TV section count – it’s 1
  • Get TV row count for section 0 (actual category) – (original count plus one for the new row)

At this point, both UITableView and Core Data throw a fit, because things are out of whack.  Specifically, Core Data lets you know that there’s only one section in your table view, but it started out with two, and there were no additions or deletions.

This could probably be solved by keeping better track of what sections exist and were changed by altering the item’s category, but this strikes me as trying to do NSFetchedResultsController’s job for it.  I’m now moving back to just one FRC, with a custom sort descriptor.  I’ll worry about implementing features down the road when I get to that point.

1 comment

  1. Thanks. Points me to the right direction. But sequentializing two sorting descriptors is pretty damn complicated, relearning predicates now..

Leave a comment

Your email address will not be published. Required fields are marked *