TEAM LICENSES: Save money and learn new skills through a Hacking with Swift+ team license >>

SwiftUI: Day 19 Conversion Help

Forums > 100 Days of SwiftUI

I am trying to dynamically create the parameters that are needed to pass into the measurement argument and then similarly for the conversion function, but my attempt to creat a string that looks like e.g. UnitSpeed.metersPerSecond and pass that as a variable into the Measurement or converted parameters is barking loudly. I could do this the long-handed way and create a bunch of if statements, but this seems like the most elegant route, if I can figure out how to pass the unit selections into the parameteres:

(also...how do I add an image here and I will show a screenshot of where I am)

(https://www.dropbox.com/scl/fi/o4qfavz573z4ittkj2x9n/Screenshot-2024-01-30-at-10.04.13-PM.png?rlkey=ftypf5afzfewpfwkdowq6cl5r&dl=0https://)

2      

Well, I went back and forth with Bard a few times...OMG... and the key insight is to use from: wihtin the unit area of Measurement, like this:

Measurement(value: inValue, unit: unit(from: inputUnit))

This is where I ended up:

import SwiftUI

struct ContentView: View {
    @State private var inValue = 10.0
    @State private var inputUnit = "m/s"
    @State private var outputUnit = "mph"

    let inUnit = ["m/s", "km/h", "mph", "kn"]
    let outUnit = ["m/s", "km/h", "mph", "kn"]

    func unit(from unitString: String) -> UnitSpeed {
        switch unitString {
        case "m/s":  return .metersPerSecond
        case "mph":   return .milesPerHour
        case "kn":    return .knots
        case "km/h":  return .kilometersPerHour
        default:      return .metersPerSecond
        }
    }

    var body: some View {
        NavigationStack {
            Form {
                Section("Enter Speed:") {
                    TextField("Input Speed", value: $inValue, format: .number)
                }

                Section("Select Incoming Speed Unit:") {
                    Picker("", selection: $inputUnit) {
                        ForEach(inUnit, id: \.self) {
                            Text($0)
                        }
                    }
                }

                Section("Select Outgoing Speed Unit:") {
                    Picker("", selection: $outputUnit) {
                        ForEach(outUnit, id: \.self) {
                            Text($0)
                        }
                    }
                }

                Section("Converted Speed") {
                    let convertMe = Measurement(value: inValue, unit: unit(from: inputUnit))
                    let convertOut = unit(from: outputUnit)
                    let convertedSpeed = convertMe.converted(to: convertOut)
                    Text(convertedSpeed.formatted())
                }
            }
            .navigationTitle("Conversion")
        }
    }
}

#Preview {
    ContentView()
}

2      

You might think to use this approach. Why do you need to convert back and forth strings when you can store measurements in array and use them.

struct ContentView: View {
    @State private var inValue = 10.0
    @State private var inputValue: Dimension = UnitSpeed.metersPerSecond
    @State private var outputValue: Dimension = UnitSpeed.milesPerHour

    let formatter: MeasurementFormatter

    var result: String {
        let inputMeasurement = Measurement(value: inValue, unit: inputValue)
        let outputMeasurement = inputMeasurement.converted(to: outputValue)
        return formatter.string(from: outputMeasurement)
    }

    var unitTypes: [Dimension] = [
        UnitSpeed.metersPerSecond,
        UnitSpeed.milesPerHour,
        UnitSpeed.kilometersPerHour,
        UnitSpeed.knots
    ]

    init() {
        formatter = MeasurementFormatter()
        formatter.unitOptions = .providedUnit
        formatter.unitStyle = .short
    }

    var body: some View {
        Form {

            Section("Enter amount here") {
                TextField("Amount", value: $inValue, format: .number)
                    .keyboardType(.decimalPad)
            }

            Section("From unit") {
                Picker("Unit from", selection: $inputValue) {
                    ForEach(unitTypes, id: \.self) {
                        Text(formatter.string(from: $0))
                            .tag($0)
                    }
                }
                .pickerStyle(.segmented)
            }

            Section("To unit") {
                Picker("To Unit", selection: $outputValue) {
                    ForEach(unitTypes, id: \.self) {
                        Text(formatter.string(from: $0))
                            .tag($0)
                    }
                }
                .pickerStyle(.segmented)

            }

            Section("Result") {
                Text(result)
            }
        }
    }
}

As for how to post images from dropbox see that post https://www.hackingwithswift.com/forums/100-days-of-swiftui/day-six-loops/25082/25091

2      

@ygeras Yes, I wanted to do that. Thanks for showing me how to format the unit like that.

2      

@obelix thanks...I'm learning. :)

2      

Hacking with Swift is sponsored by Blaze.

SPONSORED Still waiting on your CI build? Speed it up ~3x with Blaze - change one line, pay less, keep your existing GitHub workflows. First 25 HWS readers to use code HACKING at checkout get 50% off the first year. Try it now for free!

Reserve your spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.