它已经发生了!期待已久的CoreData
的继任者已发行了SwiftData
!尽管SwiftData
保留了CoreData
的某些特性(使用相同的存储架构),但它确实使我们能够使用简单的声明代码持续存在数据。对于Swift开发人员来说,这似乎可能是改变游戏规则的人,因此我立即必须检查一下。
当我探讨了SwiftData
的基本用例时,我注意到SwiftData
的使用降至6个步骤左右。在本文中,我将指导您使用SwiftData
构建一个简单的待办事项应用程序,从而阐明这些基本步骤。本文将不涵盖应用程序的UI实现,因为重点是SwiftData
。
这是我们将要介绍的六个步骤:
-
import SwiftData
. - 创建模型:为数据定义类。
- 将您的模型设置为
modelContainer
:这使SwiftData知道它将使用哪些数据。 - 在您的观点中声明
@Environment(\.modelContext)
:这确立了您的数据存在并受到操纵的上下文。 - 前缀
@Query
到一个数组变量:访问您存储的数据的包装器。 - 与您的CRUD操作的上下文互动。
让我们从更详细地研究这些步骤中开始。
1.导入SwiftData
第一步是到import SwiftData
。是的,我知道这很明显,但有时我们都忘记了。
import SwiftData
2.创建模型
过去,当使用CoreData
时,您将打开一个.xcdatamodel
文件并通过添加“ add entity”来实现实体。在SwiftData
中,我们只需使用@Model
与普通的Swift类型建模数据。在这里,我将@Model
包装器放在数据类ToDoItem
上方。该模型将代表我们的待办事项列表中的各个任务。每个任务都将具有标题,内容和添加的日期。
@Model
class ToDoItem {
let title: String
let content: String
let dateAdded: Date
init(title: String, content: String, dateAdded: Date = .init()) {
self.title = title
self.content = content
self.dateAdded = dateAdded
}
}
3.在App
中设置.modelContainer()
在SwiftData
中,.modelContainer()
用于在应用程序中为您的数据模型建立存储区域或“容器”。将其视为指定应用程序中的特定空间以存储ToDoItem
模型的所有数据实例。
在主应用程序结构中设置了容器(在这种情况下,SwiftDataToDoExampleApp
,因为这可以确保在整个应用程序中访问数据。
@main
struct SwiftDataToDoExampleApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(for: ToDoItem.self)
}
}
在此代码段中,.modelContainer(for: ToDoItem.self)
添加到WindowGroup
中。这告诉应用程序创建专门针对ToDoItem
实例的存储区域。现在,无论我们在应用程序中的何处,我们都可以操纵我们的待办事项。
4.在您看来声明@Environment(\.modelContext)
接下来,在您的视图中声明@environment(.modelcontext)。 @Environment(\.modelContext)
允许我们从容器中阅读。这听起来有些复杂,但这本质上是从步骤3中建立您的视图与存储在模型范围内的数据之间的连接的一种方法。换句话说,它的作用就像门户一样,我们的视图可以用来与ModelContainer进行交互。
struct ContentView: View {
@Environment(\.modelContext) var context
// ...
}
5.前缀@Query
到数组变量
在SwiftUI
视图中,您可以使用包装器@Query
获取数据。 SwiftData
和SwiftUI
一起工作,当基础数据更改时,视图将自动更新,并使用最新数据进行更新。
@Query var items: [ToDoItem]
就像在CoreData
中一样,您可以将SortDescriptor
和Predicate
添加到获取中。在下面的情况下,ToDoItem
将以添加时的相反顺序显示。
@Query(FetchDescriptor(sortBy: [SortDescriptor(\.dateAdded, order: .reverse)]),animation: .snappy) private var items: [ToDoItem]
6.与您的上下文互动以进行CRUD操作
现在,我们已经完成了模型,容器,上下文以及与视图进行通信的方式的设置,现在该是时候与我们的上下文进行交互了。与上下文的第一个交互是将数据(ToDoItem
)插入上下文。将ToDoItem
插入上下文之后,请不要忘记保存它。这是一个两步的过程,对上下文所做的更改将通过保存来最终确定。
在下面的摘要中,我创建了两个函数来插入该项目,然后将其保存到上下文中。
func insert(_ item: ToDoItem) {
context.insert(item)
save()
}
func save() {
do {
try context.save()
} catch {
print(error.localizedDescription)
}
}
删除也是如此。从上下文中删除,然后保存到上下文以确保已更新。
func delete(_ item: ToDoItem) {
context.delete(item)
save()
}
以及上述6个步骤,我们已将SwiftData
实施到我们的待办事项应用中。我将在下面包含所有UI代码,以便您可以看到我如何整理整个项目。可以随意将其复制并粘贴到Xcode中。
最后,请记住,SwiftData
仍在Beta中,它可能会随机崩溃,尤其是在保存后。我想,随着Xcode 15来自Beta,这些问题将被更新。
应用屏幕截图
代码
contentvievice.swoft
import SwiftUI
import SwiftData
struct ContentView: View {
@Environment(\.modelContext) var context
@Query var items: [ToDoItem]
@State private var showingSheet: Bool = false
@State private var title: String = ""
@State private var content: String = ""
var body: some View {
NavigationStack {
List {
ForEach(items) { item in
VStack(alignment: .leading) {
HStack(alignment: .top) {
Text(item.title)
.bold()
Spacer()
Text(item.dateAdded.formatted(date: .numeric, time: .shortened))
.font(.caption)
.foregroundStyle(.gray)
}
Text(item.content)
.font(.subheadline)
}
.swipeActions(content: {
Button(action: {
self.delete(item)
}, label: {
Label("Delete", systemImage: "xmark.bin.fill")
})
.tint(Color.red)
})
}
}
.navigationTitle("To Do List")
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button {
showingSheet.toggle()
} label: {
Image(systemName: "plus")
}
}
}
.sheet(isPresented: $showingSheet, content: {
Form {
Section {
TextField("Add the title...", text: $title)
} header: {
Text("Title")
}
Section {
TextEditor(text: $content)
} header: {
Text("Content / Notes")
}
Section {
Button("Add Item") {
let item = ToDoItem(title: title, content: content)
insert(item)
showingSheet = false
title = ""
content = ""
}
.disabled(title.isEmpty || content.isEmpty)
}
}
})
}
}
func insert(_ item: ToDoItem) {
context.insert(item)
save()
}
func delete(_ item: ToDoItem) {
context.delete(item)
save()
}
func save() {
do {
try context.save()
} catch {
print(error.localizedDescription)
}
}
}
todoitem.swift
import SwiftUI
import SwiftData
@Model
class ToDoItem {
let title: String
let content: String
let dateAdded: Date
init(title: String, content: String, dateAdded: Date = .init()) {
self.title = title
self.content = content
self.dateAdded = dateAdded
}
}
swiftdatatodoexampleapp.swift
import SwiftUI
@main
struct SwiftDataToDoExampleApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(for: ToDoItem.self)
}
}
感谢您查看帖子。
最好!
Dean Thompson
跟着我!
LinkedIn
Twitter
Instagram
参考
使用KavSoft的SwiftData
的很好示例亚历山大·洛根(Alexander Logan)的精彩文章。还深入介绍了与关系使用SwiftData:Alexander Logan's Blog