SwiftData 学习笔记:增删改查
前言
在上一篇文章中,我们简单介绍了 SwiftData 的使用场景,以及举了一个非常简单使用示例。在本篇文章中,我们将进行更加详细的介绍 SwiftData 的增删改查操作。
对于增删改查来说,最简单的应该就是查询的操作。所以我们先从查询开始。
查询
一句代码就能实现查询:
@Query private var items: [Item]
@Query 是非常强大的,当视图出现的时候它会立即从 SwiftData 中加载所有的缓存的数据模型。而且它会监测数据库的所有改变,当你对缓存的对象进行添加、删除、修改操作时,你获取的 items 也会进行同步更新。
删除
你可以通过对你的模型上下文调用 delete() 函数,来进行对 SwiftData 存储对象的删除。
示例代码如下:
@Model
final class Item {
var timestamp: Date
var name: String
init(timestamp: Date, name: String) {
self.timestamp = timestamp
self.name = name
}
}
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@Query private var items: [Item]
var body: some View {
NavigationSplitView {
List {
ForEach(items) { item in
let text = "Item at \(item.timestamp), name: \(item.name)"
NavigationLink {
Text(text)
} label: {
Text(text)
}
}
.onDelete(perform: deleteItems)
}
} detail: {
Text("Select an item")
}
}
private func deleteItems(offsets: IndexSet) {
withAnimation {
for index in offsets {
modelContext.delete(items[index])
}
}
}
}
在上述代码中,我们使用 ForEach 去迭代 SwiftData 查询出的所有数据。因此,我们现在可以使用 SwiftUI 编写与任何数据数组相同的删除方法。
最后,在 ForEach 后面加上 OnDelete() 修饰符就可以了:
.onDelete(perform: deleteItems)
这样,我们就完成了删除操作。删除操作完事之后,接下来我们看一下如何进行修改操作。
修改
我们需要编写一个详情页来进行 Item 的修改操作。新建一个名为 ItemDetailView 的 SwiftUI 文件,导入 SwiftData:
struct ItemDetailView: View {
@Bindable var item: Item
var body: some View {
Form {
TextField("Name", text: $item.name)
}
.navigationTitle("Edit Item")
}
}
#Preview {
do {
let config = ModelConfiguration(isStoredInMemoryOnly: true)
let example = Item(timestamp: Date(), name: "Default")
return ItemDetailView(item: example)
.modelContainer(container)
} catch {
fatalError("Error")
}
}
首先,我们需要声明一个属性用来接收外界传递进来的数据:item。因为我们是需要在详情页修改首页传递进来的数据,并且首页要同步这个修改。所以我们需要用 @Bindable 修饰 item。
接着,我们在 body 中使用 Form 包裹一下 TextField 控件,这样页面的布局会比较美观,并没有别的逻辑作用。然后使用 TextField 来进行 name 的修改。
这样,我们的逻辑代码已经写完了。但 Preview 还需要我们处理一下,它是编译不过的。因为 SwiftData 不知道在哪里创建数据,这里并没有可用的模型容器或上下文。预览页面的代码分下面四步:
- 创建自定义
ModelConfiguration对象,并指定只要内存缓存。 - 使用创建的
config来创建模型容器。 - 创建一个
Item类型的示例对象。 - 将创建的模型容器和示例对象传递给
ItemDetailView。
Tips:如果你创建的 SwiftData 模型对象并没有被模型容器所包含,你的预览页面会崩溃。
最后,再将 ContentView 的代码修改如下即可:
List {
ForEach(items) { item in
let text = "Item at \(item.timestamp), name: \(item.name)"
NavigationLink {
ItemDetailView(item: item) // 此处代码
} label: {
Text(text)
}
}
.onDelete(perform: deleteItems)
}
这就完成了修改操作的全部改动。此时运行项目,在详情页的修改之后,再返回首页你会看到 name 会被同步修改。
添加
添加跟删除操作很类似:
private func addItem() {
let newItem = Item(timestamp: Date(), name: "default")
modelContext.insert(newItem)
}
新建一个 Item 类型的对象,然后调用模型上下文(modelContext)的 insert 函数将其传递进去即可。
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
然后将其当做给按钮的点击事件即可。