I have a UITableViewController
, which is a delegate for an NSFetchedResultsController
. My NSFetchedResultsControllerDelegate
functions are set up as per "Typical Use" in Apple's documentation, with the table view controller as the fetched result controller's delegate property.
I also have some view controllers which are presented on top of the table view where the managed objects can be modified. These modifications are done on the same managed object context. There is only one managed object context constructed in my application, and it is accessed globally. (I have put some print
statements in my object context construction just to be sure I am not accidentally re-constructing it elsewhere.)
When I modify one of the managed objects, the delegate function controller:didChangeObject
is called, but the NSFetchedResultsChangeType
is always .Delete
. When I create a managed object, the delegate function does not fire at all.
However, when I manually call call performFetch()
and tableView.reloadData()
, the cells are restored to the correct state: the removed row comes back, any not-inserted rows are created.
The result is that deleting an object works as expected (the cell is removed), but updates to an object cause its cell to be removed, and object creations do not trigger cell inserts.
I tried to create a simple demo of this behaviour, but when I re-created the situation from a blank application, I don't see this behaviour. So something within my application is causing this strange behaviour, but I can't figure out what. Any ideas?
Extra Info:
The actual construction of the predicate and sort descriptors are done over several different classes, but printing them via print(resultsController.fetchRequest.predicate)
and print(resultsController.fetchRequest.sortDescriptors)
gives the following:
Optional(readState == "2" OR readState == "1")
Optional([(readState, ascending, compare:), (title, ascending, compare:)])
I have put a print statement in my controller:didChangeObject:
method, and I can see that this only gets called with type.rawValue = 2
(i.e. .Delete
), and only when I modify objects, not when I create them.
It's an inconsistency with how NSFetchedResultsController
handles its NSPredicate
.
If the NSFetchedResultsController
is constructed with a fetch request which has a predicate which does a comparison between an integer and a string like follows:
let predicate = NSPredicate(format: "integerAttribute == %@", String(1))
this will lead to the predicate string being:
integerAttribute == "1"
When this is the case, initial fetches work fine: calling the function performFetch()
on the fetched results controller returns all objects where the integerAttribute
is equal to 1
(where integerAttribute
is of type Int32
).
However, the notifications to NSFetchedResultsControllerDelegate
do not work fine. Modifications of managed objects result in the delegate being notified of a NSFetchedResultsChangeType.Delete
change. Creations of managed objects do not invoke the delegate at all.
To make all this weirdness go away, fix the predicate format string as follows:
let predicate = NSPredicate(format: "integerAttribute == %d", 1)