在 SwiftUI 中将 @FetchRequest 与 Core Data 一起使用时修改 nil 排序行为
Posted
技术标签:
【中文标题】在 SwiftUI 中将 @FetchRequest 与 Core Data 一起使用时修改 nil 排序行为【英文标题】:Modify nil sort behavior when using @FetchRequest with Core Data in SwiftUI 【发布时间】:2020-02-23 19:17:42 【问题描述】:我正在 SwiftUI 中从 Core Data 中获取实体,并希望像这样对它们进行排序:
-
如果有下一个日期,按升序排序
在那些有下一个日期的下方,按创建日期对剩余的进行排序
我有:
@FetchRequest(entity: MyEntity.entity(), sortDescriptors: [
NSSortDescriptor(keyPath: \MyEntity.nextDate, ascending: true),
NSSortDescriptor(keyPath: \MyEntity.dateCreated, ascending: true)
]) private var entities: FetchedResults<MyEntity>
问题是那些没有下一个日期的人都排在那些有非零下一个日期的人之上,如other question所示。
我尝试继承 NSSortDescriptor
以将 nil
值移动到末尾,但它从不调用任何被覆盖的函数。
final class NilsLastSortDescriptor: NSSortDescriptor
override func copy(with zone: NSZone? = nil) -> Any
return NilsLastSortDescriptor(key: self.key, ascending: self.ascending, selector: self.selector)
override var reversedSortDescriptor: Any
return NilsLastSortDescriptor(key: self.key, ascending: !self.ascending, selector: self.selector)
override func compare(_ object1: Any, to object2: Any) -> ComparisonResult
if (object1 as AnyObject).value(forKey: self.key!) == nil && (object2 as AnyObject).value(forKey: self.key!) == nil
return .orderedSame
if (object1 as AnyObject).value(forKey: self.key!) == nil
return .orderedDescending
if (object2 as AnyObject).value(forKey: self.key!) == nil
return .orderedAscending
return super.compare(object1, to: object2)
我也尝试使用包含比较器块的NSSortDescriptor
API,但是这会崩溃
例外:“不支持的 NSSortDescriptor(比较器块不是 支持)”
如何实现所需的排序行为?
【问题讨论】:
请展示您如何在@FetchRequest 中调用子类 NSSortDescriptor @E.Coms 更新 【参考方案1】:@FetchRequest 使用排序描述符作为获取请求的一部分,因此您不能在获取请求的定义中使用比较器块(至少不能使用 SQLite 存储)。但是,您可以使用 sorted(by:) 对 fetch (entities
) 的结果进行排序,作为视图的 body
处理的一部分:
var body: some View
VStack
List
ForEach(self.entities.sorted(by: first, second in
if first.nextDate == nil && second.nextDate == nil return (first.dateCreated <= second.dateCreated)
if first.nextDate == nil return false
if second.nextDate == nil return true
if first.nextDate! == second.nextDate! return (first.dateCreated <= second.dateCreated)
return (first.nextDate! < second.nextDate!)
), id: \.self) myEntity in
// Your code for your cells...
...
为了简单起见,我假设dateCreated
是非可选的。如果不是,您将需要修改排序谓词以处理 nil 值。它也可能写得更漂亮 - 但我希望你能明白。
只是要注意它是在内存中排序的,因此不知道此解决方案的性能和/或内存影响。
【讨论】:
【参考方案2】:在 CoreData 中,排序仅使用 NSString 类中的方法,例如“compare:”或“localizedStandardCompare:”之类的。
由于在大多数情况下您无法覆盖这些方法,甚至无法更改它们,您可以考虑其他解决方法。
您可以设置Special Date
,而不是“Nil”日期,如果所需数据为“Nil”,则该日期非常晚。通过这种方式,您可以将这些日期排序到底部。
您可能不会显示这些特殊日期,或者在 SwiftView 中将它们显示为“Nil”。
您可以只玩NSString
游戏,而不是subclass
【讨论】:
以上是关于在 SwiftUI 中将 @FetchRequest 与 Core Data 一起使用时修改 nil 排序行为的主要内容,如果未能解决你的问题,请参考以下文章