core-data - 带有 CoreData 的 TextField
问题描述
目标:使用 coredata 在具有 CRUD 功能的列表中拥有无限的 TextField。
目标示例,但没有 Coredata:
struct Item: Identifiable {
let id = UUID()
var title: String
}
class TestItems: ObservableObject {
@Published var items = [Item]()
}
struct ContentView: View {
@ObservedObject var itemGroup = TestItems()
var body: some View {
NavigationView{
List{
ForEach(itemGroup.items.indices, id:\.self) { index in
TextField("Type Stuff Here", text: $itemGroup.items[index].title)
}
.onDelete(perform: removeRows)
}
.navigationBarTitle("Working Example")
.navigationBarItems(trailing: Button(action: {
let stuff = Item(title: "")
itemGroup.items.append(stuff)
}, label: {
Text("Add")
}))
}
}
func removeRows(at offsets: IndexSet) {
itemGroup.items.remove(atOffsets: offsets)
}
}
我对 Coredata 的尝试:
import SwiftUI
import CoreData
struct ContentView: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
sortDescriptors: [
NSSortDescriptor(keyPath: \Item.timestamp, ascending: true),
NSSortDescriptor(keyPath: \Item.title, ascending: true)
],
animation: .default)
private var items: FetchedResults<Item>
var body: some View {
NavigationView{
List {
ForEach(items) { item in
TextField("Type Response Here", text: $item.title) //<-- This returns an error "cannot find item in scope"
}
.onDelete(perform: deleteItems)
}
.navigationBarTitle("CoreData")
.navigationBarItems(trailing: Button(action: {
addItem()
}, label: {
Text("Add Item")
}))
}
}
private func addItem() {
withAnimation {
let newItem = Item(context: viewContext)
newItem.timestamp = Date()
newItem.title = "Hello"
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}
private func deleteItems(offsets: IndexSet) {
withAnimation {
offsets.map { items[$0] }.forEach(viewContext.delete)
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}
}
我还尝试将结构和类与 Coredata 一起使用(如我的示例),但如果可能的话,我无法找到将类保存到 Coredata 中的方法。
解决方案
您需要使用ObservedObject
CoreData 对象,为此最好为行创建单独的子视图,例如
ForEach(items) { item in
ItemView(item: item)
}
和ItemView
struct ItemView: View {
@ObservedObject var item: Item
var body: some View {
// now binding over item title is provided by ObservedObject wrapper
TextField("Type Response Here", text: $item.title)
}
}
更新:可选属性的处理可能会有所不同,具体取决于预期的行为。这是可能的变体:
var body: some View {
let text = Binding(
get: { item.title ?? "" },
set: { item.title = $0 }
)
TextField("Type Response Here", text: text)
}
注意:在字段中输入文本不会保存 CoreData 对象,因此您需要考虑将其保存在哪里,可能的变体在.onCommit
for 中TextField
。
推荐阅读
- python - 在排序一个列表期间将不同列表中的相关元素保持在一起
- c# - 如何对通用列表对象进行排序
- javascript - 向和从 js 服务器发送数据的基本方法?
- json - 使用 Pyspark 处理 JSON 结构
- amazon-web-services - 为什么角色假设应该在 lambda 内部完成?
- html - 如何将数值绑定到 CSS 以创建时间线?
- docker - 如何为 docker compose 环境变量设置运行时变量
- javascript - 仅在 Javascript 中具有不同段落的动态 Div
- tsql - 表格模型中的测量列未在浏览器中显示正确的值
- javascript - 调用此函数时如何获取返回值?