SwiftUI——Core Data数据库的使用(在纯SwiftUI生命周期中)
Core Data数据库在SwiftUI中使用起来不难,不过很多文章写的都是Swift中的使用方法,很少有纯SwiftUI的Core Data数据库的使用方法。我就想着自己来整理一下,写出来,如果有错误,欢迎指正~开始前的准备如果是新建项目的话,创建项目的时候选择上“Use Core Data”然后点击Next进入项目。把ContentView.swift文件中苹果预设的代码删光,改成以下代码:s
Core Data数据库在SwiftUI中使用起来不难,不过很多文章写的都是Swift中的使用方法,很少有纯SwiftUI的Core Data数据库的使用方法。我就想着自己来整理一下,写出来,如果有错误,欢迎指正~
开始前的准备
如果是新建项目的话,创建项目的时候选择上“Use Core Data”
然后点击Next进入项目。把ContentView.swift文件中苹果预设的代码删光,改成以下代码:
struct ContentView: View {
//我们可以要求它提供当前托管对象内容,并将其分配给一个属性供我们使用
@Environment(\.managedObjectContext) private var viewContext
var body: some View {
VStack {
Button("Add") {
//这里我们等会添加按钮的功能
}
List {
//显示Core Data数据库内容的列表
}
}
}
}
然后进入Persistence.swift
文件,将第16~19行的以下代码删除掉,并且空出来位置:
for _ in 0..<10 {
let newItem = Item(context: viewContext)
newItem.timestamp = Date()
}
最后进入项目名称.xcdatamodeld
文件,选中“ENTITIES”下预先给定的“Item”,按Delete键删除。
如果是在已有项目中添加Core Data,按住CMD+N键,新建一个项目名称.xcdatamodeld
文件,如下:
然后再新建一个名为Persistence.swift
的swift文件,如下:
然后将以下代码覆盖进去(需要注意的是,要将container = NSPersistentContainer(name: "Test")
里的Test
改成你的项目名称):
import CoreData
struct PersistenceController {
static let shared = PersistenceController()
static var preview: PersistenceController = {
let result = PersistenceController(inMemory: true)
let viewContext = result.container.viewContext
//留出来供后面使用的区域
do {
try viewContext.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
return result
}()
let container: NSPersistentContainer
init(inMemory: Bool = false) {
container = NSPersistentContainer(name: "Test")
if inMemory {
container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
}
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
}
}
然后在需要调用数据库的View的struct中写入以下代码:
//我们可以要求它提供当前托管对象内容,并将其分配给一个属性供我们使用
@Environment(\.managedObjectContext) private var viewContext
不过为了方便介绍,假设需要调用数据的View的代码如下:
struct ContentView: View {
//我们可以要求它提供当前托管对象内容,并将其分配给一个属性供我们使用
@Environment(\.managedObjectContext) private var viewContext
var body: some View {
VStack {
Button("Add") {
//这里我们等会添加按钮的功能
}
List {
//显示Core Data数据库内容的列表
}
}
}
}
这样准备工作就做好了。
添加Entity
我们选中项目名称.xcdatamodeld
文件,然后点击下面的“Add Entity”,来添加一个Entity,如下:
接下来我们双击新建的“”Entity来修改名称,这里修改成“Person”,并且点击“Attributes”下面的加号,添加两个attribute。双击第一个,将其命名为“id”,“Type”一栏选择“UUID”;双击第二个,将其命名为“name”,“Type”一栏选择“String”,如下:
添加初始数据
在Core Data数据库中,有一个很奇怪的特性——如果数据库是空的,就会报错,哪怕第一个动作是添加数据。所以一开始就要预先放入一个或者多个值(这个值只会出现在preview中,运行在虚拟机或者真正的机器上的时候则不会显示)。这时候我们就需要选中Persistence.swift
文件,到我们之前预留出来的地方,输入我们预先填充的数据,例如:
//留出来供后面使用的区域
let newPerson = Person(context: viewContext)
newPerson.name = ""
这时候会报错,如果Entity的名称没拼写错误,就不用管。可能是缓存bug,不影响使用。
获取数据库中的数据
我们在View的结构体中输入:
@FetchRequest(entity: Person.entity(), sortDescriptors: [])
var persons: FetchedResults<Person>
这样我们就算激活了数据库,可以获取/删除数据了。
我们先来定义一个数组,来向数据库中输入数据,假设为:
let nameArray: [String] = ["张三","李四","王五","赵六"]
我们将代码修改一下,方便我们观察数据库的写入,修改为如下:
struct ContentView: View {
//我们可以要求它提供当前托管对象内容,并将其分配给一个属性供我们使用
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(entity: Person.entity(), sortDescriptors: [])
var persons: FetchedResults<Person>
var body: some View {
VStack {
Button("添加") {
//随机获取姓名
let chosenName = nameArray.randomElement()!
//给数据库写入数据
let person = Person(context: self.viewContext)
person.id = UUID()
person.name = "\(chosenName)"
//保存当前数据
try? self.viewContext.save()
}
List {
//将数据库中的name数据依次列出
ForEach(persons, id: \.id) { person in
Text(person.name!)
}
}
}
}
}
这时候效果如下:
点击一下添加,效果如下:
这时候报错的话就不用在意,因为是不影响运行的bug。如果实在很在意的话,关闭项目重新打开一下就好了
开发中,就只需要将随机获取数组中数据的代码改成获取用户输入即可。
按特定顺序获取数据
这时候我们多点几下可以发现他是按照输入顺序来添加到List中的,也就是说是按照添加顺序来输出的。如果我们这时候想按照名字排序输出,当然我门可以在Foreach部分设定一个过滤器,不过有更简单的办法,如下:
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Person.name, ascending: true)],
animation: .default)
var persons: FetchedResults<Person>
看sortDescriptors
属性,这是个数组,之前我们设置为空。现在我们将其内容设定成NSSortDescriptor(keyPath: \Person.name, ascending: true)
,这表示按照Person的name属性进行排序,也就是按照名称排序。
这时候我们点击“添加”按钮就能发现,如果随机的姓名是一样的,新添加的就会排在同一个名字的上面。
删除数据
我们在Foreach下添加.onDelete
,苹果官方的代码如下:
private func deleteItems(offsets: IndexSet) {
withAnimation {
offsets.map { persons[$0] }.forEach(viewContext.delete)
do {
try viewContext.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}
然后我们修改一下view body部分,这时候当前界面的代码如下:
let nameArray: [String] = ["张三","李四","王五","赵六"]
struct ContentView: View {
//我们可以要求它提供当前托管对象内容,并将其分配给一个属性供我们使用
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Person.name, ascending: true)],
animation: .default)
var persons: FetchedResults<Person>
var body: some View {
VStack {
Button("添加") {
//随机获取姓名
let chosenName = nameArray.randomElement()!
//给数据库写入数据
let person = Person(context: self.viewContext)
person.id = UUID()
person.name = "\(chosenName)"
//保存当前数据
try? self.viewContext.save()
}
List {
//将数据库中的name数据依次列出
ForEach(persons, id: \.id) { person in
Text(person.name!)
}
.onDelete(perform: deleteItems )
}
}
}
private func deleteItems(offsets: IndexSet) {
withAnimation {
offsets.map { persons[$0] }.forEach(viewContext.delete)
do {
try viewContext.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}
}
然后我们运行preview,点击“添加”,右划新添加的内容,效果如下:
这时候我们就可以删除数据库内容了。
以上就是Core Data在纯SwiftUI生命周期中的使用方法,不复杂,就是为了详细写了比较多,希望能帮的有需要的人。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)