如何获取 TextField 来显示核心数据实体的属性?

问题描述 投票:0回答:1

我有一份水果清单。结构体

FruitRowView
提供每行视图的布局。在这个
FruitRowView
中,有一个
TextField
,我想显示每种水果的名称。我在做这件事时遇到了麻烦。我之所以想使用
TextField
而不是
Text
来显示每个水果的名称,是为了让用户可以轻松地从
TextField
编辑水果的名称。在本例中,水果是核心数据实体,水果名称是该实体的属性。

这是我的核心数据类:

class CoreDataViewModel: ObservableObject {
    
    let container: NSPersistentContainer
    @Published var savedEntities: [FruitEntity] = []
    
    init() {
        container = NSPersistentContainer(name: "FruitsContainer")
        container.loadPersistentStores { (description, error) in
            if let error = error {
                print("Error with coreData. \(error)")
            }
        }
        fetchFruits()
    }
    
    func fetchFruits() {
        let request = NSFetchRequest<FruitEntity>(entityName: "FruitEntity")
        
        do {
            savedEntities = try container.viewContext.fetch(request)
        } catch let error {
            print("Error fetching. \(error)")
        }
    }
    
    func addFruit(text: String) {
        let newFruit = FruitEntity(context: container.viewContext)
        newFruit.name = text
        saveData()
    }
    
    func saveData() {
        do {
            try container.viewContext.save()
            fetchFruits()
        } catch let error {
            print("Error saving. \(error)")
        }
    }
}

这是我的内容视图:

struct ContentView: View {
    
    //sheet variable
    @State var showSheet: Bool = false
    @StateObject var vm = CoreDataViewModel()
    @State var refresh: Bool
    
    var body: some View {
        NavigationView {
            VStack(spacing: 20) {
               
                Button(action: {
                    showSheet.toggle()
                }, label: {
                    Text("Add Fruit")
                })
                
                List {
                    ForEach(vm.savedEntities) { fruit in
                        FruitRowView(vm: vm, fruit: fruit)
                    }
                }
            }
            .navigationTitle("Fruits")
            .sheet(isPresented: $showSheet, content: {
                SecondScreen(refresh: $refresh, vm: vm)
            })
        }
    }
}

这是我的弹出屏幕(用于创建新水果)

struct SecondScreen: View {
    
    @Binding var refresh: Bool
    @Environment(\.presentationMode) var presentationMode
    @ObservedObject var vm: CoreDataViewModel
    @State var textFieldText: String = ""
    
    var body: some View {
        TextField("Add fruit here...", text: $textFieldText)
            .font(.headline)
            .padding(.horizontal)
        
        Button(action: {
            guard !textFieldText.isEmpty else { return }
            vm.addFruit(text: textFieldText)
            textFieldText = ""
            presentationMode.wrappedValue.dismiss()
            refresh.toggle()
        }, label: {
            Text("Save")
        })
    }
}

这是我的 FruitRowView:

struct FruitRowView: View {
    
    //instance of core data model
    @ObservedObject var vm: CoreDataViewModel
    var fruit: FruitEntity
    @State var fruitName = fruit.name

    var body: some View {
        TextField("Enter fruit name", text: $fruitName)
    }
}

所以我得到的错误是:

无法在属性初始值设定项中使用实例成员“fruit”;属性初始值设定项在“self”可用之前运行。

当我尝试将

FruitRowView
分配给
fruitName
时,
fruit.name
中会出现此错误。我认为有一个简单的解决方法,但我一直无法弄清楚。

swift list swiftui binding textfield
1个回答
0
投票

由于视图模型中的fruitEntities是已发布的属性,因此行中不需要状态变量。您需要行视图的绑定,并且应该在内容视图中传递它。

您也不需要将视图模型传递给行视图。

struct FruitRowView: View {

    // No need to pass view model to child, only pass the data
    // @ObservedObject var vm: CoreDataViewModel

    @Binding var fruitName: String

    // You don't need this.
    // @State var fruitName = fruit.name

    var body: some View {
        TextField("Enter fruit name", text: $fruitName)
    }
}

struct ContentView: View {
    ...
    List {
        ForEach(vm.savedEntities) { fruit in
            FruitRowView(fruitName: $fruit.name)
        }
    }
    ...
}
© www.soinside.com 2019 - 2024. All rights reserved.