第5章:视图集成与数据流
如何在 SwiftUI 视图中使用 @Query
1. @Query 宏的基本用法
@Query 是 SwiftData 与 SwiftUI 深度集成的核心特性,允许以声明式方式在视图中直接绑定数据查询:
import SwiftData
import SwiftUI
struct BookListView: View {
@Query(sort: \Book.title) private var books: [Book]
var body: some View {
List(books) { book in
Text(book.title)
}
}
}
关键特性:
- 自动数据绑定:当底层数据变化时视图自动更新
- 零样板代码:无需手动处理
ModelContext或FetchRequest - 编译时安全:属性路径通过KeyPath验证
2. 配置查询参数
@Query支持完整的查询配置能力:
// 完整参数配置示例
@Query(
filter: #Predicate<Book> { $0.rating > 3 },
sort: [SortDescriptor(\Book.publishDate, order: .reverse)],
animation: .default
) var topRatedBooks: [Book]
可配置项:
| 参数 | 类型 | 说明 |
|---|---|---|
filter | #Predicate | 使用Swift原生谓词语法 |
sort | SortDescriptor | 单字段或多字段排序 |
animation | Animation? | 数据变化时的过渡动画 |
3. 动态查询更新
通过参数绑定实现动态查询:
struct CategoryView: View {
let selectedCategory: String
var body: some View {
// 当selectedCategory变化时自动重新查询
BookList(category: selectedCategory)
}
}
struct BookList: View {
let category: String
@Query var books: [Book]
init(category: String) {
_books = Query(
filter: #Predicate { $0.category == category },
sort: \Book.title
)
}
}
4. 与@Environment的协同工作
最佳实践是将@Query与SwiftUI环境值结合使用:
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.modelContainer(for: Book.self)
}
}
}
struct ContentView: View {
@Environment(\.modelContext) private var context
@Query var books: [Book]
func deleteBook(_ book: Book) {
context.delete(book)
}
}
5. 性能优化提示
- 分页加载:
@Query(sort: \Book.title, limit: 50) var firstPage: [Book]
- 避免过度更新:
// 对于不频繁变化的数据
@Query(animation: nil) var staticData: [Author]
- 派生属性处理:
@Query var books: [Book]
var count: Int { books.count } // 避免在body中直接计算
var body: some View {
Text("Total: \(count)")
}
常见问题解决方案
Q:为什么我的视图没有自动更新? A:检查是否满足以下条件:
- 确保
@Model对象类遵循Observable协议 - 修改操作需在
modelContext的上下文中执行 - 主线程规则:所有修改必须在主线程进行
Q:如何强制刷新查询? A:重建查询条件或使用modelContext.refresh(_:)方法:
@State private var refreshFlag = false
@Query(filter: #Predicate<Book> { _ in true },
animation: .default)
var books: [Book]
通过系统化的@Query使用,开发者可以构建出既高效又响应迅速的数据驱动型UI界面。
