SwiftUI: как объединить Double со строкой и выполнить математический расчет? - PullRequest
0 голосов
/ 04 августа 2020

Я все еще новичок в Swift / SwiftUI и кодировании в целом. Я задавал этот вопрос раньше, но он был закрыт, потому что он, по-видимому, был дубликатом, но (!) Это не учитывает SwiftUI, и я не могу заставить эту вещь работать в SwiftUI, потому что даже если я использую предложенное NSExpression, я не могу использовать результат, потому что это не представление, и я понятия не имею, как преобразовать его в представление (см. обновление в конце вопроса).

Я пытаюсь сделать простой преобразователь с набором предопределенное преобразование из DataModel. Пока я могу заполнить ContentView и перейти в DetailView, где я создал ползунок, который автоматически обновляет TextView всякий раз, когда ползунок перемещается, и весь экран заполняется через DataModel (надеюсь, я объясню это правильно).

Теперь моя проблема в том, что каждое преобразование, очевидно, использует разные вычисления. Например, «/ 1000» или «* 50». Я сохранил эти части как строки в DataModel. Теперь я хотел бы использовать эти строки в своих вычислениях, но я понятия не имею, как их включить. Очевидно, я не могу преобразовать их в двойные значения для расчета. Вот код и DataModel:

DataModel:

struct Converter: Identifiable {
    var id = UUID()
    var title: String
    var range = 0.0...0.0
    var calc: String
    var sliderValue: Double

    var color: [Color]
    var description: String
}

Как вы можете видеть, «cal c» имеет тип String. Я также использую "диапазон", который я определил с 0,0 ... 0,0, потому что я не знал, как я могу его инициализировать в противном случае (я всегда получал ошибку из-за закрытого диапазона (?), Так что это то, что я использовал с чтобы заглушить ошибку.

Вот пример некоторых данных:

let converterData: [Converter] = [
    Converter(
        title: "Conversion1",
        range: 0.0...200,
        calc: "/ 1000",
        sliderValue: 0.0,
        color: [Color.blue, Color.red],
        description: "This is conversion 1"
     ),
...
...

Как видите, я изменил диапазон на «0,0 ... 200», потому что ползунок не должен ' t go за пределами 200. Я ввел часть расчета "/ 1000" в cal c. Это то, что я хотел бы добавить к расчету в DetailView (см. ниже). Я не использую остальные данные прямо сейчас, потому что я все еще придерживаюсь этого расчета.

Код:

@State var sliderValue: Double = 0.0
var conversion: Converter

var body: some View {
    VStack(alignment: .leading) {
        VStack(alignment: .leading) {
            Text("value1".uppercased())
                .font(.largeTitle)
                .fontWeight(.bold)
            Text("\(sliderValue, specifier: "%.2f")")
                .font(.system(size: 60, weight: .bold))
            Text("to value2".uppercased())
                .font(.largeTitle)
                .fontWeight(.bold)
        
            self.calculatedView(for: sliderValue)
        }
    
        Slider(value: $sliderValue, in: conversion.range, step: 0.5)
            .padding(8)
            .overlay(
                Capsule()
                    .stroke(Color.purple, style: StrokeStyle(lineWidth: 5))
            )
    }
    .padding()
}

Как видите, я использую "convert.range ", чтобы указать точный диапазон для ползунка. Вот расчет:

private func calculatedView(for value: Double) -> some View {
    Text("\(value / 1000, specifier: "%.2f")")
        .font(.system(size: 60, weight: .bold))
    }
}

Обновление:

Итак, я попытался использовать NSExpression в calculateView :

private func calculatedView(for value: Double) -> some View {
    
    let calculation = String(value) + conversion.calc
    let expn = NSExpression(format:calculation)
    let result = expn.expressionValue(with: nil, context: nil)
    
    Text(result)
        .font(.system(size: 60, weight: .bold))
}

Я даже не уверен, что это способ использования NSExpression. Я пытаюсь создать съел строку из значения ползунка и добавил convert.cal c. Он должен выглядеть примерно так: 125,5 / 1000 (как пример). Я не уверен, что это вообще правильно. Теперь я пытаюсь использовать NSExpression и сохранять результат в переменной result, и эта переменная должна отображаться как TextView. Я получаю два сообщения об ошибках:

  1. Функция объявляет непрозрачный тип возврата, но не имеет операторов возврата в своем теле, из которых можно вывести базовый тип

И для текста ( результат): 2. Нет точных совпадений при вызове инициализатора

Вопрос

Прямо сейчас я просто добавляю значение и жестко кодирую «/ 1000» в. Что Я бы хотел изменить, вместо этого использовать convert.cal c (который равен "/ 1000). Но, очевидно, когда я просто добавляю это, весь расчет прерывается, но я понятия не имею, как переформатировать все это так что это работает. Раньше я бы просто создал оператор switch (или что-то еще) с новым вычислением для каждого преобразования, которое взорвало бы весь код.

Я действительно надеюсь, что кто-то сможет указать мне на правильное направлении, потому что я так счастлив, что наконец понял, как использовать простую модель данных.

Спасибо за чтение и за любые советы. С уважением!

1 Ответ

0 голосов
/ 04 августа 2020

Скорее свойство cal c в Конвертере удерживает закрытие. Таким образом, вы можете передать любую функцию преобразования при инициализации Converter (путем передачи замыкания преобразования). Выполняйте все вычисления в формате Double (как числа), а затем конвертируйте в строку для отображения.

Вот ссылка на Closures на Swift.org

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

EDIT Простой пример использования Closure

Все остальное то же самое, за исключением переменной cal c

struct Converter {
    var calc: ((Double) -> Double)
}

Использование

let closure: ((Double) -> Double) = { num in
        return num / 1000
}

let converter = Converter(calc: closure)

print("Conversion result: \(converter.calc(500))")

Вы можете передать любой метод расчета в конвертер, или вы можете усложнить метод в самой структуре и просто вызвать cal c, который автоматически захватит любые переменные в структуре.

Но для вашей проблемы вместо функции CalculatedView:

VStack(alignment: .leading) {
        Text("value1".uppercased())
            .font(.largeTitle)
            .fontWeight(.bold)
        Text("\(sliderValue, specifier: "%.2f")")
            .font(.system(size: 60, weight: .bold))
        Text("to value2".uppercased())
            .font(.largeTitle)
            .fontWeight(.bold)
    
        Text("\(conversion.calc(sliderValue))")
            .font(.system(size: 60, weight: .bold))
    }
...