问题描述
我正在尝试学习如何使用核心数据"保存,编辑和删除数据.到目前为止,在这个强大的社区的帮助下,我已经成功地保存和删除了,但是我不知道如何编辑和更新当前保存的数据.
I am trying to learn how to Save, Edit and Delete data using Core Data. So far, with the help of this great community, I have managed to Save and Delete, but I don't know how to Edit and Update currently saved data.
这是我正在开发的应用程序的简单示例.这是包含来自核心数据的项目的列表.我在模态(AddItemView)上添加新的列表条目,并在EditItemView上删除它们.我也想在AddItemView视图上编辑和更新数据.
Here is a simple example of an app I am working on. It is a list with items from Core Data. I am adding new list entries on a modal (AddItemView) and deleting them on EditItemView.I would like to edit and update data as well on the AddItemView view.
我设法将数据传递给TextField的提示,但是我想要的是:
I managed to pass data to hint of TextField, but what I wanted is:
- 将当前数据传递到TextField的文本并使其可编辑
- 点击后保存/更新数据
- pass the current data to text of TextField and make it editable
- Save/update the data after tapping
核心数据有1个实体:ToDoItem.它具有1个属性:title(字符串).代码:类定义,模块:当前产品模块.
Core Data has 1 Entity: ToDoItem. It has 1 Attribute: title (String). Codegen: Class Definition, Module: Current Product Module.
我在代码中添加了一些其他注释.
I have added some additional comments in the code.
ContentView
import SwiftUI
struct ContentView: View {
@Environment(\.managedObjectContext) var managedObjectContext
@FetchRequest(
entity: ToDoItem.entity(),
sortDescriptors: [
NSSortDescriptor(keyPath: \ToDoItem.title, ascending: true)
]
) var toDoItems: FetchedResults<ToDoItem>
@State private var show_modal: Bool = false
var body: some View {
NavigationView {
List{
ForEach(toDoItems, id: \.self) {todoItem in
NavigationLink(destination: EditItemView(todoItem: todoItem)) {
Text(todoItem.title ?? "")
.font(.headline)
}
}
}
.navigationBarTitle(Text("My List"))
.navigationBarItems(trailing:
Button(action: {
self.show_modal = true
}) {
Text("Add")
}.sheet(isPresented: self.$show_modal) {
AddItemView().environment(\.managedObjectContext, self.managedObjectContext)
}
)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
return ContentView().environment(\.managedObjectContext, context)
}
}
AddItemView
import SwiftUI
struct AddItemView: View {
@Environment(\.presentationMode) var presentationMode
@Environment(\.managedObjectContext) var managedObjectContext
@State private var title = ""
var body: some View {
NavigationView {
ScrollView {
TextField("to do item...", text: $title)
.font(Font.system(size: 30))
Spacer()
}
.padding()
.navigationBarTitle(Text("Add Item"))
.navigationBarItems(
leading:
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
Text("Cancel")
},
trailing:
Button(action: {
let toDoItem = ToDoItem(context: self.managedObjectContext)
toDoItem.title = self.title
do {
try self.managedObjectContext.save()
}catch{
print(error)
}
self.presentationMode.wrappedValue.dismiss()
}) {
Text("Done")
}
)
}
}
}
struct AddItemView_Previews: PreviewProvider {
static var previews: some View {
AddItemView()
}
}
EditItemView
import SwiftUI
struct EditItemView: View {
@Environment(\.managedObjectContext) var managedObjectContext
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
var todoItem: ToDoItem
//I am only using this newTitle variable, because I don't know how to properly bind TextField to todoItem.title
@State private var newTitle = ""
var body: some View {
ScrollView {
TextField(todoItem.title != nil ? "\(todoItem.title!)" : "", text: $newTitle)
//TextField("to do...", text: (todoItem.title != nil ? "\(todoItem.title!)" : ""))
//ERROR
//I need something like the above, but this gives me an error: Cannot convert value of type 'String' to expected argument type 'Binding<String>'
}
.padding()
.navigationBarTitle(Text("Edit item"))
.navigationBarItems(
trailing:
Button(action: {
print("Delete")
self.managedObjectContext.delete(self.todoItem)
do {
try self.managedObjectContext.save()
self.presentationMode.wrappedValue.dismiss()
}catch{
print(error)
}
}) {
Text("Delete")
.foregroundColor(.red)
}
)
}
}
struct EditItemView_Previews: PreviewProvider {
static var previews: some View {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
//Test data
let todoItem = ToDoItem.init(context: context)
todoItem.title = "Title"
return EditItemView(todoItem: todoItem).environment(\.managedObjectContext, context)
}
}
推荐答案
我将通过以下方式进行
TextField("_here_is_label_name_", text: $newTitle, onCommit: {
self.todoItem.title = self.newTitle
try? self.managedObjectContext.save()
})
.onAppear {
self.newTitle = self.todoItem.title != nil ? "\(self.todoItem.title!)" : ""
}
.onDisappear {
self.todoItem.title = self.newTitle
try? self.managedObjectContext.save()
}
更新:添加了.onDisappear
修饰符;可以使用专用的私有功能提取重复的代码,以进行良好的设计.
Update: added .onDisappear
modifier; duplicated code can be extracted in dedicated private function to have good design.
这篇关于如何用Core Data中的数据填充TextField并更新更改?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!