When using a UUID
property of NSManagedObject
in an NSFetchedResultsController
, the application crashes with:
-[__NSConcreteUUID compare:]: unrecognized selector sent to instance
when the contents of NSFetchedResultsController.fetchedObjects
change, but not when it is first loaded. When first loaded, the objects are sorted correctly by UUID.
This is how I create the NSFetchedResultsController
:
let fetchRequest: NSFetchRequest<MyObject> = MyObject.fetchRequest()
fetchRequest.sortDescriptors = [
NSSortDescriptor(key: #keyPath(MyObject.uuid), ascending: true),
]
fetchRequest.predicate = NSPredicate(format: "%K == %@", #keyPath(MyObject.tag), tag)
let controller = NSFetchedResultsController(fetchRequest: fetchRequest,
managedObjectContext: context,
sectionNameKeyPath: nil,
cacheName: nil)
controller.delegate = self
do {
try controller.performFetch()
} catch {
fatalError("###\(#function): Failed to performFetch: \(error)")
}
To create the NSManagedObject
(MyObject
in the code above), I used the model editor to add a field "uuid" with the UUID
type.
It seems that Core Data has no problem sorting by UUID at the SQL level, but after it loads the data and tries to maintain the sorting in memory, it tries to call compare
on _NSConcreteUUID
in some way, which doesn't exist as a method. This method could be implemented with byte or string comparison of the UUID.
Failed attempts:
compare
as an extension to UUID
or NSUUID
comparator
argument to NSSortDescriptor
is not allowed by Core Data and will terminate the applicationMaybe there is a workaround by using Transformable
that will let it benefit from the native UUID type on the SQL side, but still be usable inside NSFetchedResultsController
?
No, it's not possible to sort Core Data results using a UUID
property. You would need to convert the UUID to a string if you want to use it for sorting.
Core Data doesn't actually sort on UUIDs when fetching. You can see this if you turn on Core Data SQLite debugging by adding -com.apple.CoreData.SQLDebug 4
to the arguments in the build scheme in Xcode. When you sort on a numerical property like a time stamp, the debug output includes a SQL ORDER BY
clause
CoreData: sql: SELECT 0, t0.Z_PK FROM ZEVENT t0 ORDER BY t0.ZTIMESTAMP DESC
If you try it with a UUID
property, there's no ORDER BY
clause. Core Data just ignores the sort descriptor. It won't crash but it's not sorting the results either.
I'm not sure why this is, because using the sqlite3
command line tool to open up the SQLite file Core Data creates shows that a UUID property is represented as a SQLite BLOB
field. SQLite can sort on BLOB
, even though it doesn't usually make sense to do so.
I suggest filing a bug with Apple. I don't know what they'll think about how this should work, but it should definitely not ignore the sort descriptor and not print a console message of some kind.