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:
- Adding
compareas an extension toUUIDorNSUUID - Passing the
comparatorargument toNSSortDescriptoris not allowed by Core Data and will terminate the application
Maybe 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
UUIDproperty. 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 4to the arguments in the build scheme in Xcode. When you sort on a numerical property like a time stamp, the debug output includes a SQLORDER BYclauseIf you try it with a
UUIDproperty, there's noORDER BYclause. 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
sqlite3command line tool to open up the SQLite file Core Data creates shows that a UUID property is represented as a SQLiteBLOBfield. SQLite can sort onBLOB, 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.