是否可以在 NSFetchedResultsController 的 NSSortDescriptor 中使用 UUID?
Is it possible to use a UUID in an NSSortDescriptor for NSFetchedResultsController?
在 NSFetchedResultsController
中使用 UUID
属性 of NSManagedObject
时,应用程序崩溃:
-[__NSConcreteUUID compare:]: unrecognized selector sent to instance
当 NSFetchedResultsController.fetchedObjects
的内容发生变化时,而不是首次加载时。首次加载时,对象按 UUID 正确排序。
这就是我创建 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)")
}
为了创建 NSManagedObject
(上面代码中的 MyObject
),我使用模型编辑器添加了一个 UUID
类型的字段“uuid”。
似乎Core Data在SQL级别按UUID排序没有问题,但在加载数据并尝试在内存中保持排序后,它会尝试调用compare
_NSConcreteUUID
以某种方式,它不作为一种方法存在。此方法可以通过 UUID 的字节或字符串比较来实现。
失败的尝试:
- 添加
compare
作为 UUID
或 NSUUID
的扩展
- Core Data 不允许将
comparator
参数传递给 NSSortDescriptor
,这将终止应用程序
也许有一个使用 Transformable
的变通方法可以让它从 SQL 端的本机 UUID 类型中获益,但在 NSFetchedResultsController
内部仍然可用?
不,无法使用 UUID
属性 对核心数据结果进行排序。如果要使用 UUID 进行排序,则需要将 UUID 转换为字符串。
Core Data 在获取时实际上并不按 UUID 排序。如果您通过将 -com.apple.CoreData.SQLDebug 4
添加到 Xcode 中的构建方案中的参数来打开 Core Data SQLite 调试,您可以看到这一点。当您像时间戳一样对数字 属性 进行排序时,调试输出包括 SQL ORDER BY
子句
CoreData: sql: SELECT 0, t0.Z_PK FROM ZEVENT t0 ORDER BY t0.ZTIMESTAMP DESC
如果您尝试使用 UUID
属性,则没有 ORDER BY
子句。核心数据只是忽略排序描述符。它不会崩溃,但也不会对结果进行排序。
我不确定这是为什么,因为使用 sqlite3
命令行工具打开 Core Data 创建的 SQLite 文件显示表示了一个 UUID 属性作为 SQLite BLOB
字段。 SQLite 可以按 BLOB
排序,尽管这样做通常没有意义。
我建议向 Apple 提交错误。我不知道他们会怎么想这应该如何工作,但它绝对不应该忽略排序描述符并且不打印某种控制台消息。
在 NSFetchedResultsController
中使用 UUID
属性 of NSManagedObject
时,应用程序崩溃:
-[__NSConcreteUUID compare:]: unrecognized selector sent to instance
当 NSFetchedResultsController.fetchedObjects
的内容发生变化时,而不是首次加载时。首次加载时,对象按 UUID 正确排序。
这就是我创建 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)")
}
为了创建 NSManagedObject
(上面代码中的 MyObject
),我使用模型编辑器添加了一个 UUID
类型的字段“uuid”。
似乎Core Data在SQL级别按UUID排序没有问题,但在加载数据并尝试在内存中保持排序后,它会尝试调用compare
_NSConcreteUUID
以某种方式,它不作为一种方法存在。此方法可以通过 UUID 的字节或字符串比较来实现。
失败的尝试:
- 添加
compare
作为UUID
或NSUUID
的扩展
- Core Data 不允许将
comparator
参数传递给NSSortDescriptor
,这将终止应用程序
也许有一个使用 Transformable
的变通方法可以让它从 SQL 端的本机 UUID 类型中获益,但在 NSFetchedResultsController
内部仍然可用?
不,无法使用 UUID
属性 对核心数据结果进行排序。如果要使用 UUID 进行排序,则需要将 UUID 转换为字符串。
Core Data 在获取时实际上并不按 UUID 排序。如果您通过将 -com.apple.CoreData.SQLDebug 4
添加到 Xcode 中的构建方案中的参数来打开 Core Data SQLite 调试,您可以看到这一点。当您像时间戳一样对数字 属性 进行排序时,调试输出包括 SQL ORDER BY
子句
CoreData: sql: SELECT 0, t0.Z_PK FROM ZEVENT t0 ORDER BY t0.ZTIMESTAMP DESC
如果您尝试使用 UUID
属性,则没有 ORDER BY
子句。核心数据只是忽略排序描述符。它不会崩溃,但也不会对结果进行排序。
我不确定这是为什么,因为使用 sqlite3
命令行工具打开 Core Data 创建的 SQLite 文件显示表示了一个 UUID 属性作为 SQLite BLOB
字段。 SQLite 可以按 BLOB
排序,尽管这样做通常没有意义。
我建议向 Apple 提交错误。我不知道他们会怎么想这应该如何工作,但它绝对不应该忽略排序描述符并且不打印某种控制台消息。