编辑核心数据对象动态列表的详细信息
Posted
技术标签:
【中文标题】编辑核心数据对象动态列表的详细信息【英文标题】:Edit details of a dynamic list of core data object 【发布时间】:2021-02-28 14:41:35 【问题描述】:我使用 Xcode 默认的 CoreData 模板来构建我的应用程序。 我曾尝试使用 CoreData 并创建这样的实体:
然后我创建了一个 AddItemView,它允许我将项目添加到视图中。
struct AddItemView: View
@Environment(\.managedObjectContext) var viewContext
@Environment(\.presentationMode) var presentationMode
@State private var notes = ""
@State private var selectedDate = Date()
var body: some View
NavigationView
Form
Section
TextField("notes", text: $notes)
Section
DatePicker("", selection: $selectedDate, displayedComponents: .date)
Text("Your selected date: \(selectedDate)")
Section
Button("Save")
let newItem = Item(context: self.viewContext)
newItem.notes = self.notes
newItem.recordDate = self.selectedDate
newItem.timestamp = Date()
try? self.viewContext.save()
self.presentationMode.wrappedValue.dismiss()
.navigationBarTitle("Add Item")
它运行良好,可以添加项目。
然后我想单击每个项目以转到详细信息视图。在 DetailView 中,应该有一个编辑按钮,让我可以修改对象。
因此我为此目的创建了三个文件:ItemHost、DetailView、EditorView
项目的导航目的地将转到 ItemHost。
struct ItemListView: View
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)],
animation: .default)
private var items: FetchedResults<Item>
@State private var showingAddScreen = false
var body: some View
NavigationView
List
ForEach(items, id: \.self) item in
NavigationLink(destination: ItemHost(item: item))
VStack
Text("Item at \(item.timestamp!, formatter: FormatterUtility.dateTimeFormatter)")
Text("notes: \(item.notes ?? "")")
Text("Item Date: \(item.recordDate!, formatter: FormatterUtility.dateFormatter)")
.onDelete(perform: deleteItems)
.toolbar
ToolbarItem(placement: .navigationBarLeading)
#if os(ios)
EditButton()
#endif
ToolbarItem(placement: .navigationBarTrailing)
Button(action: self.showingAddScreen.toggle())
Label("Add Item", systemImage: "plus")
.sheet(isPresented: $showingAddScreen)
AddItemView().environment(\.managedObjectContext, self.viewContext)
ItemHost如下:
struct ItemHost: View
@Environment(\.editMode) var editMode
@Environment(\.managedObjectContext) var contextView
@State var item: Item
var body: some View
NavigationView
if editMode?.wrappedValue == .active
Button("Cancel")
editMode?.animation().wrappedValue = .inactive
if editMode?.wrappedValue == .inactive
ItemDetailView(item: item)
else
ItemEditor(item: item)
.navigationBarTitle("EditMode Problem")
.navigationBarItems(trailing: EditButton())
DetailView只是一个显示细节的视图,没有什么特别的。
struct ItemDetailView: View
@Environment(\.managedObjectContext) var contextView
@Environment(\.presentationMode) var presentationMode
@State private var showingDeleteAlert = false
let item: Item
var body: some View
VStack
Text("notes: \(item.notes ?? "")")
Text("Record Date: \(item.recordDate!, formatter: FormatterUtility.dateFormatter)")
.navigationBarTitle(Text("Item Detail"), displayMode: .inline)
.alert(isPresented: $showingDeleteAlert)
Alert(title: Text("Delete Item"), message: Text("Are you sure?"),
primaryButton: .destructive(Text("Delete"))
self.deleteItem()
, secondaryButton: .cancel()
)
.navigationBarItems(trailing: Button(action:
self.showingDeleteAlert = true
)
Image(systemName: "trash")
)
// Problem here
// Can delete the item and go back to list page. But the actual item in the CoreData has not been removed. If I call contextView.save() it will crash.
func deleteItem()
contextView.delete(item)
presentationMode.wrappedValue.dismiss()
EditorView 是这样的:
struct ItemEditor: View
@Environment(\.presentationMode) var presentation
@State var item: Item
var body: some View
List
HStack
Text("Notes").bold()
TextField("Notes", text: $item.notes) // Error
// Error
DatePicker(selection: $item.recordDate, displayedComponents: .date)
Text("Record Date").bold()
这里有几个问题:
ItemEditor:无法将“Binding
单击单个导航项后,将不会显示任何内容。我希望它最初(不是编辑模式)然后显示详细视图。如果是编辑模式,则显示编辑器。
我对@binding 以及如何将项目传递到 DetailView 和编辑器感到困惑。编辑器如何将数据保存回 contextView 中的 item 对象?
-
对于 ItemDetailView 中的 deleteItem()。它可以删除该项目并显然返回到 ItemListView。但是,当我退出应用程序,然后再次运行时。我发现该项目再次出现,并没有真正删除。
现在单击该项目,它会显示:
【问题讨论】:
那是很多代码,我注意到的东西很少,你已经用“状态”属性包装器标记了你的“项目”实体,核心数据实体是 ManagedObject 子类,而不是结构,所以你应该' t 用“状态”标记它们,而不是使用 ObservedObject,因为它们已经默认确认 ObservableObjects 协议。我想这就是为什么你看不到更新发生的原因。 【参考方案1】:不要在 Core Data 中使用 @State 来改变 Item。您应该改用@ObservedObject。更新数据后,它将刷新父视图。 请阅读这篇文章: https://purple.telstra.com/blog/swiftui---state-vs--stateobject-vs--observedobject-vs--environme
【讨论】:
以上是关于编辑核心数据对象动态列表的详细信息的主要内容,如果未能解决你的问题,请参考以下文章