繁体   English   中英

在 SwiftUI 中使用 @FetchRequest 和 Core Data 时修改 nil 排序行为

[英]Modify nil sort behavior when using @FetchRequest with Core Data in SwiftUI

我正在从 SwiftUI 中的核心数据中获取实体,并希望像这样对它们进行排序:

  1. 如果有下一个日期,将它们升序排序
  2. 在有下一个日期的下方,按创建日期对剩余的进行排序

我有:

@FetchRequest(entity: MyEntity.entity(), sortDescriptors: [
    NSSortDescriptor(keyPath: \MyEntity.nextDate, ascending: true),
    NSSortDescriptor(keyPath: \MyEntity.dateCreated, ascending: true)
]) private var entities: FetchedResults<MyEntity>

问题是那些没有下一个日期的人都排在那些下一个日期非零的人之上,如 this 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 使用排序描述符作为获取请求的一部分,因此您不能在获取请求的定义中使用比较器块(至少不能使用 SQLite 存储)。 但是,您可以使用sorted(by:)对获取( 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 值。 它可能也可以写得更漂亮 - 但我希望你明白了。

请注意它在 memory 中排序,因此不知道此解决方案的性能和/或 memory 影响。

在 CoreData 中,排序仅使用 NSString class 中的方法,例如“compare:”或“localizedStandardCompare:”之类的方法。

由于在大多数情况下您无法覆盖这些方法甚至无法更改它们,因此您可以考虑其他解决方法。

如果所需数据为“无”,您可以设置一个非常晚的Special Date ,而不是“无”日期。 通过这种方式,您可以将这些日期排序到底部。 您可能不会显示这些特殊日期,或在 SwiftView 中将它们显示为“Nil”。

你可以只玩NSString游戏,而不是subclass

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM