如何基于超过 1 个状态创建动态计算

How to create a dynamic calculation based off more than 1 State

我是 Swift 的新手(一般来说是编码)。我正在开发一个应用程序,该应用程序将根据对两个状态的跟踪输出计算结果。这两个状态是 brewModel 和 waterAmount。我能够成功创建一个函数,该函数将 return 基于两种状态进行一次计算。但是,现在我正在尝试创建一个选择器,它将在两个测量值(克和汤匙)之间切换计算。这是我遇到问题的地方。

我尝试用不同的方式编写一系列条件语句,例如 if 和 else if 以及 switch cases,但它不起作用。当我构建模拟器时,Xcode 只会思考很长时间,直到我停止它。有时我会在手动停止后收到错误消息,有时却不会。今天我收到“命令编译Swift来源失败,退出代码非零。”

有人有什么建议吗?

此外,如果我的代码混乱,我深表歉意,我有一堆我正在玩的东西被注释掉了。 func computeGrinds 确实有效,但仅用于一次计算。谢谢!

import SwiftUI


struct Water: View {
    //    @EnvironmentObject var favorites: Favorites
    @State var animationInProgress = true
    @State var brewModel: BrewModel
    @State var waterAmount: Int = 1
    
    @State var grindsSelection = "tbsp"
    var grindOptions = ["tbsp", "grams"]
    
    //    var resultGrindCalc: Double {
    //
    //        var value = Double(0)
    //    }
    //    switch grindsSelection {
    //    case "tbsp" || brewModel.frenchPress:
    //        value = Double(waterAmount) * 2.5
    //
    //    }
    //
    
//    func computeGrinds () -> Double {
//        switch brewModel {
//        case .frenchPress, .chemex:
//            return (2.5 * Double(waterAmount))
//        case .drip :
//            return Double(2 * Double(waterAmount))
//        case .mokaPot:
//            return Double(1 * Double(waterAmount))
//        case .aeroPress:
//            return Double(1.6 * Double(waterAmount))
//            //        default:
//            //            return(1 * Double(waterAmount))
//        }
//    }
    var body: some View {
        VStack (spacing: 5) {
            Spacer()
            HStack {
                //                Text("").padding(20)
                Text("How many cups do you want to brew?")
                
                Picker("", selection: $waterAmount) {
                    ForEach(1...15, id: \.self){
                        Text("\([=10=])")
                    }
                }
                //                Spacer()
            }.padding()
                .overlay (
                    RoundedRectangle(cornerRadius: 16)
                        .stroke(Color("Custom Color"), lineWidth: 8)
                )
            
            //            gif/image conditionals
            if (brewModel == .frenchPress) {
                LottieView(name: "frenchpress", loopMode: .loop)
            } else if brewModel == .chemex {
                LottieView(name: "pourover", loopMode: .loop)
            } else if brewModel == .aeroPress {
                LottieView(name: "aeropress", loopMode: .loop)
            } else if brewModel == .mokaPot {
                LottieView(name: "mokapot", loopMode: .loop)
            } else if brewModel == .drip {
                Image("Drip")
                    .resizable()
                    .scaledToFit()
            }
            // I would have more conditionals but testing with just these two for now
            var testingCalcCond = Double
            if (brewModel == .frenchPress)||(grindsSelection=="tbsp") {
                testingCalcCond = (2.5 * Double(waterAmount))
            } else if (brewModel == .frenchPress)||(grindsSelection=="grams") {
                testingCalcCond = (16 * Double(waterAmount))
            }
            
            let formatted = String(format: "%.2f", testingCalcCond)
//            let formatted = String(format: "%.2f", computeGrinds())
            
            HStack {
                Text("**\(formatted)**")
                Picker("Select Grinds Units: ", selection: $grindsSelection, content: {
                    ForEach(grindOptions, id: \.self) {
                        Text([=10=])
                    }
                }).onChange(of: grindsSelection) { _ in    computeGrinds()  }
                Text("of coffee grinds needed")
                
            }
            .padding()
            .overlay (
                RoundedRectangle(cornerRadius: 16)
                    .stroke(Color("Custom Color"), lineWidth: 8)
            )
            
        }
        Spacer()
    }
}


struct Water_Previews: PreviewProvider {
    static var previews: some View {
           Water(brewModel: .drip)
        }
    }
}

*我正在使用 Xcode 13.2.1 *我正在使用 swiftUI

您需要考虑两个方面:

1.如何根据输入更新结果值。
您的结果值基于两个输入:brewModel 和 waterAmount。两者都是@State 变量并由选择器更改。 我将您的 computeGrinds func 更改为计算 属性,因为当两个基值之一发生变化时将自动调用它。然后就不再需要 .onchange 了,你可以只使用 var 值——它总是最新的。

2。从汤匙重新计算为克
这更像是一个数学问题:据我了解,对于 .frenchPress,您需要每杯 2.5 汤匙或 16 克。所以 1 汤匙 = 16 / 2.5 = 6.4 克。一旦你知道你只需要通过一次 switch case,然后使用 unitValue 重新计算。我也整合了它 ;)

这是我的简化代码:

enum BrewModel {
    case frenchPress
    case chemex
    case drip
    case mokaPot
    case aeroPress
}


struct ContentView: View {
    
    @State var animationInProgress = true
    @State var brewModel: BrewModel = .frenchPress
    @State var waterAmount: Int = 1
    
    @State var grindsSelection = "tbsp"
    let grindOptions = ["tbsp", "grams"]
    
    // computed var instead of func, does the same
    var computeGrinds: Double {
        
        // transforms tbsp = 1 to grams (= 6.4 ?)
        var unitValue: Double = 1.0
        if grindsSelection == "grams" {
            unitValue = 6.4
        }
        
        switch brewModel {
        case .frenchPress, .chemex:
            return (2.5 * unitValue * Double(waterAmount))
        case .drip :
            return Double(2 * unitValue * Double(waterAmount))
        case .mokaPot:
            return Double(1 * unitValue * Double(waterAmount))
        case .aeroPress:
            return Double(1.6 * unitValue * Double(waterAmount))
        }
    }
    
    
    var body: some View {
        VStack (spacing: 5) {
            HStack {
                Text("How many cups do you want to brew?")
                
                Picker("", selection: $waterAmount) {
                    ForEach(1...15, id: \.self){
                        Text("\([=10=])")
                    }
                }
            }
            .padding()
            .overlay (
                RoundedRectangle(cornerRadius: 16)
                    .stroke(Color.brown, lineWidth: 8)
            )
            .padding(.bottom)
            
            
            let formatted = String(format: "%.2f", computeGrinds)
            
            HStack {
                Text("**\(formatted)**")
                Picker("Select Grinds Units: ", selection: $grindsSelection, content: {
                    ForEach(grindOptions, id: \.self) {
                        Text([=10=])
                    }
                })
                
                Text("of coffee grinds needed")
                
            }
            .padding()
            .overlay (
                RoundedRectangle(cornerRadius: 16)
                    .stroke(Color.brown, lineWidth: 8)
            )
        }
    }
}