SwiftData — FetchDescriptor

FetchDescriptor 是苹果在 Swift Data 框架(WWDC23 推出)中引入的一个关键类型,用于定义数据查询的配置(过滤、排序、分页等)。它是 Swift Data 中替代 Core Data 的 NSFetchRequest 的现代化方案,完全基于 Swift 并发模型设计,支持类型安全和 Swift 原生语法。


一、核心功能 #

功能说明
数据过滤通过 Predicate 宏定义查询条件(类型安全,支持 Swift 原生类型)
数据排序使用 SortDescriptor 定义排序规则(支持多字段排序)
分页查询通过 fetchLimitoffset 实现分页加载
关系预加载通过 relationshipsToPrefetch 预加载关联数据,优化性能
结果去重使用 propertiesToFetch 指定返回字段,结合 returnsDistinctResults 去重
变更跟踪通过 includePendingChanges 控制是否包含未保存的临时数据

二、基本用法 #

1. 简单查询 #

// 查询所有 User 对象
let descriptor = FetchDescriptor<User>()
let users = try await context.fetch(descriptor)

2. 过滤 + 排序 #

// 查询年龄 >= 18 的用户,按姓名升序排列
let predicate = #Predicate<User> { $0.age >= 18 }
let sort = SortDescriptor(\User.name, order: .forward)

let descriptor = FetchDescriptor(
  predicate: predicate,
  sortBy: [sort]
)

3. 分页查询 #

// 每页 20 条数据,加载第 3 页
let descriptor = FetchDescriptor<User>(
  fetchLimit: 20,
  offset: 40  // (3-1)*20 = 40
)

4. 预加载关联数据 #

// 预加载用户的订单数据
let descriptor = FetchDescriptor<User>(
  relationshipsToPrefetch: [\.orders]
)

三、对比 Core Data 的 NSFetchRequest #

特性FetchDescriptor (Swift Data)NSFetchRequest (Core Data)
类型安全✅ 基于 Swift 泛型和 KeyPath❌ 依赖字符串 Key
并发支持✅ 原生支持 Swift async/await❌ 需手动管理线程上下文
语法简洁性✅ 使用 Swift 宏 (#Predicate)❌ 依赖 NSPredicate 字符串
关系处理✅ 直接通过 KeyPath 访问关联对象❌ 需要手动配置 relationshipKeyPaths
内存优化✅ 自动优化延迟加载✅ 类似但需手动配置

四、高级用法示例 #

1. 动态排序 #

// 根据用户选择动态切换排序字段
func dynamicSortDescriptor(by keyPath: KeyPath<User, String>) -> FetchDescriptor<User> {
  FetchDescriptor(sortBy: [SortDescriptor(keyPath, order: .forward)])
}

2. 聚合查询 #

// 计算用户平均年龄
let descriptor = FetchDescriptor<User>(
  propertiesToFetch: [\.age]
)
let ages = try await context.fetch(descriptor)
let averageAge = ages.compactMap { $0.age }.reduce(0, +) / ages.count

3. 去重查询 #

// 获取所有不重复的用户所在城市
let descriptor = FetchDescriptor<User>(
  propertiesToFetch: [\.city],
  returnsDistinctResults: true
)

五、性能优化建议 #

  1. 索引加速:对频繁查询的字段添加 @Attribute(.unique)@Attribute(.indexed)
  2. 批量加载:合理使用 fetchLimit + offset 避免一次性加载过多数据
  3. 选择性加载:通过 propertiesToFetch 仅加载必要字段
  4. 内存优化:设置 includesPropertyValues = false 当仅需对象引用时

本文共 688 字,创建于 Feb 22, 2025
相关标签: Xcode, SwiftUI