可选链接 SwiftUI 文本字段中的绑定值

dsy*_*nkd 3 swift swiftui

我有以下模型:

struct Food: Codable, Identifiable {
    var id = UUID()
    var name: String = ""
    var energy: Float?
    var water: Float?
    var macroProfile: MacronutrientProfile?
}

struct MacronutrientProfile: Codable {
    var carb: Float?
    var protein: Float?
    var fat: Float?
}
Run Code Online (Sandbox Code Playgroud)

我试图将此模型的实例的值绑定到TextField这样的:

struct FoodEditView: View {
    @State var food: Food
    var body: some View {
        Form {
            Section(header: Text("Basics").fontWeight(.bold)) {
                HStack {
                    Text("Name")
                    Spacer()
                    TextField("Name", text: $food.name)
                    .multilineTextAlignment(.trailing)
                }
                HStack {
                    Text("Energy")
                    Spacer()
                    TextField("Calories", value: $food.energy, formatter: calorie)
                    .multilineTextAlignment(.trailing)
                    .keyboardType(.numberPad)
                }
                HStack {
                    Text("Water")
                    Spacer()
                    TextField("Grams", value: $food.water, formatter: gram)
                    .multilineTextAlignment(.trailing)
                    .keyboardType(.numberPad)
                }
            }
            .textCase(.none)
            Section(header: Text("Macronutrients").fontWeight(.bold)) {
                HStack {
                    Text("Carbohydrates")
                    Spacer()
                    TextField("Grams", value: $food.macroProfile?.carb, formatter: gram)
                    .multilineTextAlignment(.trailing)
                    .keyboardType(.numberPad)
                }
                HStack {
                    Text("Protein")
                    Spacer()
                    TextField("Grams", value: $food.macroProfile?.protein, formatter: gram)
                    .multilineTextAlignment(.trailing)
                    .keyboardType(.numberPad)
                }
                HStack {
                    Text("Fat")
                    Spacer()
                    TextField("Grams", value: $food.macroProfile?.fat, formatter: gram)
                    .multilineTextAlignment(.trailing)
                    .keyboardType(.numberPad)
                }
            }
            .textCase(.none)
Run Code Online (Sandbox Code Playgroud)

我在链接时出现了很奇怪的一长串错误macroProfile

代码错误

我的问题是,为什么我在可选链接时收到这些错误macroProfile,而不是在使用energyor时收到这些错误water,这两者也是可选值?解决这个问题的最佳方法是什么?

Sco*_*son 7

当在其上使用“点链”语法时,它Binding是创建Binding. 它不具有与点语法通常具有的“查找该事物的属性”相同的语义。

因此$food.name不会解析food然后引用其属性之一的绑定。它将创造一种食物特性的Binding<String>双向方式。name

类似地,当$food.macroProfile该表达式的值是Binding<MacroNutrientProfile?>... 时,将直接更改其中的值的绑定food(并且它可以更改的值是可选的)。它不是通过$food引用该对象的属性之一来解析绑定。

$food.macroProfile?.carb是无意义的,因为它$food.macroProfile的类型Binding<MacroNutrientProfile?>不是可选类型。所以你会看到错误。

$food.name不是无意义的,因为它是 aBinding<String>并且您并没有尝试将非可选值视为可选值。

更改它的一种方法是使用自定义绑定:

struct Food: Codable, Identifiable {
    var id = UUID()
    var name: String = ""
    var energy: Float?
    var water: Float?
    var macroProfile: MacronutrientProfile?
}

struct MacronutrientProfile: Codable {
    var carb: Float?
    var protein: Float?
    var fat: Float?
}

struct SomeView : View {
    @State var food: Food
    let gram = NumberFormatter()

    var body : some View {
        let carbBinding = Binding<Float?>(get: { food.macroProfile?.carb },
                                          set: { newValue in food.macroProfile?.carb = newValue })

        return HStack {
           Text("Carbohydrates")
           Spacer()
            TextField("Grams", value: carbBinding, formatter: gram)
           .multilineTextAlignment(.trailing)
           .keyboardType(.numberPad)
       }
    }
}
Run Code Online (Sandbox Code Playgroud)