UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

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      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

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.