在 Swift 中,SortComparator
是一个用于定义排序规则的协议,它提供了一种更现代、灵活且类型安全的方式来实现排序逻辑。与 Foundation 的 SortDescriptor
相比,SortComparator
是 Swift 标准库的一部分,更深度集成 Swift 语言特性(如泛型、协议和闭包),适用于 Swift 原生集合(如 Array
)和 SwiftUI 等框架。
1. 核心概念 #
- 协议定义:
SortComparator
是一个协议,要求实现compare(_:to:)
方法。 - 内置实现:Swift 标准库为常见类型(如
Int
、String
、Date
)提供了默认的SortComparator
。 - 组合能力:支持通过多个
SortComparator
组合实现多条件排序。
2. 基本用法 #
直接使用内置比较器 #
let numbers = [5, 3, 1, 4, 2]
let sortedNumbers = numbers.sorted(using: [IntComparator()]) // [1, 2, 3, 4, 5]
let strings = ["Swift", "iOS", "Xcode"]
let sortedStrings = strings.sorted(using: [StringComparator()]) // ["iOS", "Swift", "Xcode"]
自定义排序顺序 #
// 降序排列
let descendingComparator = IntComparator(.reverse)
let sortedDescending = numbers.sorted(using: [descendingComparator]) // [5, 4, 3, 2, 1]
3. 自定义 SortComparator
#
示例 1:按字符串长度排序 #
struct StringLengthComparator: SortComparator {
typealias Compared = String
var order: SortOrder = .forward // 默认升序
func compare(_ lhs: String, _ rhs: String) -> ComparisonResult {
if lhs.count < rhs.count {
return order == .forward ? .orderedAscending : .orderedDescending
} else if lhs.count > rhs.count {
return order == .forward ? .orderedDescending : .orderedAscending
} else {
return .orderedSame
}
}
}
let strings = ["Apple", "Swift", "iOS"]
let comparator = StringLengthComparator(order: .reverse)
let sorted = strings.sorted(using: [comparator]) // ["Apple", "Swift", "iOS"]
示例 2:按自定义模型属性排序 #
struct User {
var name: String
var age: Int
}
struct UserAgeComparator: SortComparator {
typealias Compared = User
var order: SortOrder = .forward
func compare(_ lhs: User, _ rhs: User) -> ComparisonResult {
if lhs.age < rhs.age {
return order == .forward ? .orderedAscending : .orderedDescending
} else if lhs.age > rhs.age {
return order == .forward ? .orderedDescending : .orderedAscending
} else {
return .orderedSame
}
}
}
let users = [
User(name: "张三", age: 25),
User(name: "李四", age: 30),
User(name: "王五", age: 20)
]
let sortedUsers = users.sorted(using: [UserAgeComparator()])
// 结果按 age 升序排列:王五(20), 张三(25), 李四(30)
4. 多条件排序 #
组合多个比较器 #
// 先按年龄降序,再按姓名升序
let comparators: [any SortComparator] = [
UserAgeComparator(order: .reverse),
KeyPathComparator(\.name, order: .forward)
]
let sortedUsers = users.sorted(using: comparators)
// 李四(30), 张三(25), 王五(20)
使用 KeyPathComparator
#
Swift 标准库提供了 KeyPathComparator
,可直接通过键路径生成比较器:
// 按 name 升序
let nameComparator = KeyPathComparator(\.name)
// 按 age 降序
let ageComparator = KeyPathComparator(\.age, order: .reverse)
let sortedUsers = users.sorted(using: [ageComparator, nameComparator])
5. 在 SwiftUI 中的应用 #
与 @Query
结合(SwiftData)
#
struct ContentView: View {
@Query(sort: [
KeyPathComparator(\.age, order: .reverse),
KeyPathComparator(\.name)
]) var users: [User]
var body: some View {
List(users) { user in
Text("\(user.name) - \(user.age)")
}
}
}
动态切换排序条件 #
enum SortOption {
case name, age
}
struct UserListView: View {
@State private var sortOption: SortOption = .name
@State private var sortOrder: SortOrder = .forward
var body: some View {
let comparator: any SortComparator = switch sortOption {
case .name: KeyPathComparator(\.name, order: sortOrder)
case .age: KeyPathComparator(\.age, order: sortOrder)
}
List(users.sorted(using: [comparator])) { user in
// ...
}
.toolbar {
Picker("Sort By", selection: $sortOption) {
Text("Name").tag(SortOption.name)
Text("Age").tag(SortOption.age)
}
Button(sortOrder == .forward ? "↑" : "↓") {
sortOrder.toggle()
}
}
}
}
6. 与 SortDescriptor
的对比
#
特性 | SortComparator | SortDescriptor (NSSortDescriptor) |
---|---|---|
所属框架 | Swift 标准库 | Foundation 框架 |
类型安全 | 强类型(通过泛型和协议) | 弱类型(依赖字符串键路径) |
自定义能力 | 通过实现协议完全自定义逻辑 | 依赖 selector 或闭包 |
SwiftUI 集成 | 深度集成(如 @Query ) | 需转换为 NSSortDescriptor |
多条件排序 | 直接组合多个比较器 | 需手动管理数组顺序 |
性能 | 高效(编译时优化) | 略低(运行时动态派发) |
7. 最佳实践 #
优先使用
KeyPathComparator
:
对简单属性排序时,直接使用内置的KeyPathComparator
而非自定义类型。users.sorted(using: [KeyPathComparator(\.name)])
组合比较器时注意顺序:
排序条件按数组顺序优先级递减:// 先按国家,再按城市 [CountryComparator(), CityComparator()]
利用
localizedStandard
处理本地化字符串:
对用户可见的字符串排序时,优先考虑本地化规则:let comparator = StringComparator(.localizedStandard)
性能敏感场景避免复杂闭包:
对大数据集排序时,优先使用基于键路径的比较器而非闭包。
完整示例:自定义复杂排序 #
// 按用户是否是管理员 + 姓名长度排序
struct CustomUserComparator: SortComparator {
typealias Compared = User
var order: SortOrder = .forward
func compare(_ lhs: User, _ rhs: User) -> ComparisonResult {
// 管理员优先
if lhs.isAdmin && !rhs.isAdmin {
return order == .forward ? .orderedAscending : .orderedDescending
} else if !lhs.isAdmin && rhs.isAdmin {
return order == .forward ? .orderedDescending : .orderedAscending
}
// 非管理员按姓名长度排序
if lhs.name.count < rhs.name.count {
return order == .forward ? .orderedAscending : .orderedDescending
} else if lhs.name.count > rhs.name.count {
return order == .forward ? .orderedDescending : .orderedAscending
}
return .orderedSame
}
}
// 使用示例
let users = [
User(name: "Alice", isAdmin: false),
User(name: "Bob", isAdmin: true),
User(name: "Admin", isAdmin: true)
]
let sorted = users.sorted(using: [CustomUserComparator()])
// 结果:Bob (Admin, 3字母), Admin (Admin, 5字母), Alice (非Admin)
通过 SortComparator
,开发者可以构建高度定制化的排序逻辑,同时享受 Swift 类型系统和性能优化的优势。