带有 CoreData 的 TextField

Posted

技术标签:

【中文标题】带有 CoreData 的 TextField【英文标题】:TextField with CoreData 【发布时间】:2020-11-05 13:22:19 【问题描述】:

目标:使用 coredata 在列表中拥有无限的文本字段,并具有 CRUD 功能。

目标示例,但没有 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 中的方法。

【问题讨论】:

【参考方案1】:

您需要在 CoreData 对象上使用ObservedObject,为此最好为行创建单独的子视图,例如

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 中为 TextField

【讨论】:

这会引发错误“无法将 'Binding' 类型的值转换为预期的参数类型 'Binding'”我尝试强制展开但也引发了错误。 可选属性可能会根据需要以不同方式处理。查看更新。

以上是关于带有 CoreData 的 TextField的主要内容,如果未能解决你的问题,请参考以下文章

CoreData:带有privateQueueConcurrencyType的backgroundContext和子上下文之间的区别?

NSFetchRequest 带有用于递归 CoreData 实体关系的排序描述符

带有函数参数的 CoreData 谓词

CoreData - 相当于使用带有示例的类别 - Swift

如何通过带有 FetchedResults 和 CoreData 的导航链接传递数据?

带有 NSFetchResultController 的 CoreData:使用 fetchObjects 中的属性进行的无效更新