SwiftData数据查询依赖FetchDescriptor,FetchDescriptor依赖SortDescriptor进行排序。
基本形式
SortDescriptor(\.property, order: .forward)
\.property是排序的属性的KeyPath。
order是顺序:.forward = 升序,.reverse = 降序。
使用方法
1、排序字段
SortDescriptor可以排序文本、数字、日期、可选类型(nil排在最前或最后,具体取决于排序方向)。
例如:
let sortByAmount = SortDescriptor(\PiggyBank.amount, order: .reverse) // 金额从大到小
2、多重排序
SwiftData可以提供多个SortDescriptor排序。
FetchDescriptor<PiggyBank>(
sortBy: [
SortDescriptor(\.isPrimary, order: .reverse),
SortDescriptor(\.creationDate, order: .forward)
]
)
isPrimary的存钱罐排在前面,再按创建时间从早到晚排序。
3、可选值的排序行为
当属性是 Optional 类型时:
.forward 时,各类型的“nil 最前”。
.reverse 时,“nil 最后”。
注意事项
1、无法排序Bool类型
如果在SortDescriptor中,尝试排序Bool类型,会触发类型推断失败,让编译器错误地落到 Foundation 的 NSSortDescriptor 版本上。于是报出需要继承 NSObject 的错误。
Initializer 'init(_:order:)' requires that 'PiggyBank' inherit from 'NSObject'
例如:
let fetchRequest = FetchDescriptor<PiggyBank>(
sortBy: [
SortDescriptor(\.isPrimary, order: .reverse), // 发生报错
SortDescriptor(\.creationDate, order: .reverse)
]
)
因为isPrimary是布尔类型,因此发生报错。
解决方案:给Bool添加扩展,使其遵守Comparable协议:
extension Bool: Comparable {
public static func < (lhs: Bool, rhs: Bool) -> Bool {
// 定义 false 小于 true (即 0 < 1)
return !lhs && rhs
}
}
SwiftData就可以通过编译并正确生成SQL排序指令。
注:数据库层面(SQLite)本身是支持 Boolean 排序的(0和1),这个扩展只是为了通过 Swift 的类型检查。
总结
SortDescriptor配合FetchDescriptor,实现数据的排序规则。
SortDescriptor排序在数据库层面执行,不是Swift层面对数组排序,因此性能非常好,多重排序仍然可控。
升序和降序的区别在于:
升序:从小到大排序,数值小的排在前面,数值大的排在后面。
0 → 1 → 2
降序:从大到小排序,数值大的排在前面,数值小的排在后面。
2 → 1 → 0
相关文章
SwiftData查询描述符FetchDescriptor:https://fangjunyu.com/2025/11/20/swiftdata%e6%9f%a5%e8%af%a2%e6%8f%8f%e8%bf%b0%e7%ac%a6fetchdescriptor/
