Использование переменных состояния в качестве входных данных для функции в SwiftUI - PullRequest
1 голос
/ 16 июня 2019

У меня есть два текстовых поля, которые изменяют значение двух переменных @State, а именно, startMilib и endMpm, и степпер, который изменяет значение третьей переменной @State с именем fuelAdded.Я пытаюсь использовать входные данные пользователя и сделать расчет для расчета миль на галлон.На детской площадке мой код работает как положено.Однако он не работает в проекте SwiftUI.

Попытался запустить код на игровой площадке, как показано ниже:

func CalcMPG(start: String, end: String, fuel: Double) -> Int {
    let start = Int(start) ?? 1
    let end = Int(end) ?? 1
    let fuel = Int(fuel)
    let mpg = (end-start) / fuel
    return mpg
}


var endingMileage:String = "9250"
var startingMileage:String = "9000"
var fuelAdded:Double = 20

let milesPerGallon = CalcMPG(start: startingMileage, end: endingMileage, fuel: fuelAdded)
print("Fuel Efficiency: \(milesPerGallon) mpg")

Работает, как и ожидалось.

struct ContentView : View {

    @State var startingMileage: String = ""
    @State var endingMileage: String = ""
    @State var fuelAdded: Double = 10
    @State var carModel: String = ""
    @State var showMPGInfo = false
    @State var milesPerGallon: Int = 10

    func CalcMPG(start: String, end: String, fuel: Double) -> Int {
        let start = Int(start) ?? 1
        let end = Int(end) ?? 1
        let fuel = Int(fuel)
        let mpg = (end-start) / fuel
        return mpg
    }


    var body: some View {
        NavigationView {
            VStack{
                HStack {
                    Text("Car Model:")
                    Spacer()
                    TextField($carModel, placeholder: Text("Toyota Corolla"))
                        .textFieldStyle(.roundedBorder)
                }
                HStack {
                    Text("Starting ODO:")
                    Spacer()
                    TextField($startingMileage, placeholder: Text("8000"))
                    .textFieldStyle(.roundedBorder)
                    Text("miles")
                }

                HStack {
                    Text("Ending ODO:")
                    Spacer()
                    TextField($endingMileage, placeholder: Text("9000"))
                        .textFieldStyle(.roundedBorder)
                    Text("miles")
                }
                HStack {
                    Stepper(value: $fuelAdded, in: 0...20, step: 0.5) {
                        Text("Fuel Added: \(fuelAdded, specifier: "%0.1f") gallons")
                    }
                }
                Button(action: {
                    self.showMPGInfo.toggle() }){
                        Text("Show/Hide MPG")
                }
                    if showMPGInfo {
                        Spacer()
                        milesPerGallon = CalcMPG(start: startingMileage, end: endingMileage, fuel: fuelAdded)
                        Text("Fuel effiency: \(milesPerGallon) MPG")
                            .font(.largeTitle)
                    }
                }.padding()
                .navigationBarTitle(Text("Gas Mileage Calculator"))
        }
    }
}

Когдапользователь нажимает на «Показать / Скрыть MPG».Я ожидаю, что конечным полученным текстом будет «Эффективность использования топлива: xx MPG»

Однако я получаю следующие ошибки:

ContentView.swift: 34: 19: Невозможно определить тип возврата сложного замыкания;добавить явный тип для устранения неоднозначности

Это не кажется мне нигде чувственным ... Он подчеркивает начальный VStack в NavigationView.

Есть мысли?

1 Ответ

0 голосов
/ 16 июня 2019

Проблема в том, что присвоение milesPerGallon не работает с «синтаксисом компоновщика функций», используемым для построения аргументов иерархии представления. Это становится немного более очевидным, если мы заменим @State var milesPerGallon на локальную переменную (то есть есть, не содержит состояния, от которого зависит представление, только промежуточное значение):

if showMPGInfo {
    Spacer()
    let milesPerGallon = CalcMPG(start: startingMileage,
                                 end: endingMileage, fuel: fuelAdded)
    Text("Fuel effiency: \(milesPerGallon) MPG")
        .font(.largeTitle)
}

Теперь ошибка компилятора

Closure containing a declaration cannot be used with function builder 'ViewBuilder'

Для получения дополнительной информации о синтаксисе компоновщика функций см. Что включает DSL SwiftUI? (который также имеет ссылки на документацию).

Самое простое решение - избежать локальной переменной и напрямую интерполировать текст:

if showMPGInfo {
    Spacer()
    Text("Fuel effiency: \(CalcMPG(start: startingMileage, end: endingMileage, fuel: fuelAdded)) MPG")
        .font(.largeTitle)
}

Другими решениями является вычисление текстового поля в «немедленно оцененном закрытии»:

if showMPGInfo {
    Spacer();
    { () -> Text in
        let milesPerGallon = CalcMPG(start: startingMileage,
                                      end: endingMileage,
                                      fuel: fuelAdded)
        return Text("Fuel effiency: \(milesPerGallon) MPG")
    }()
    .font(.largeTitle)
}

или для определения вспомогательной функции

func resultField(start: String, end: String, fuel: Double) -> Text {
    let  milesPerGallon = CalcMPG(start: startingMileage, end: endingMileage, fuel: fuelAdded)
    return Text("Fuel effiency: \(milesPerGallon) MPG")
}

и используйте его как

if showMPGInfo {
    Spacer()
    resultField(start: startingMileage, end: endingMileage,
                fuel: fuelAdded)
        .font(.largeTitle)
}

Могут быть и другие обходные пути, но это то, что я придумал до сих пор.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...