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

100 days of SwiftUI - Day 19 challenge

Forums > 100 Days of SwiftUI

Please help me see if my solution is acceptable, or perhaps if there are better solutions or improvements please help me learn <3 (First time posting here, not sure about the format, hope I won't mess up.) Cheers.

import SwiftUI

struct ContentView: View {
    @State private var input = 0.0
    @State private var output = 0.0
    @State private var inputUnitIndex = "M"
    @State private var outputUnitIndex = "M"

    let mConvert = ["M": 1, "KM": 0.001, "FT": 3.280839, "YDS": 1.93613, "MI": 0.0006213]
    let kmConvert = ["M": 1000, "KM": 1, "FT": 3280.839, "YDS": 1936.13, "MI": 0.6213]
    let ftConvert = ["M": 0.3048, "KM": 0.0003048, "FT": 1, "YDS": 0.3333333, "MI": 0.0001893939]
    let ydConvert = ["M": 0.9144, "KM": 0.0009144, "FT": 3, "YDS": 1, "MI": 0.0005681818]
    let miConvert = ["M": 1609.344, "KM": 1.609344, "FT": 5280, "YDS": 1760, "MI": 1]

    var outcome: Double {
        var outcomeTotal: Double = 0.0
        switch inputUnitIndex {
        case "M":
            outcomeTotal = (mConvert[outputUnitIndex] ?? 0) * input
        case "KM":
            outcomeTotal = (kmConvert[outputUnitIndex] ?? 0) * input
        case "FT":
            outcomeTotal = (ftConvert[outputUnitIndex] ?? 0) * input
        case "YDS":
            outcomeTotal = (ydConvert[outputUnitIndex] ?? 0) * input
        case "MI":
            outcomeTotal = (miConvert[outputUnitIndex] ?? 0) * input
        default:
           break
        }
        return outcomeTotal
    }

    let units = ["M", "KM", "FT", "YDS", "MI"]

    var body: some View {

        NavigationStack{
            Form {

                //input
                Section {
                    Picker("UNIT", selection: $inputUnitIndex) {
                        ForEach(units, id: \.self) {
                            Text("\($0)")
                        }
                    }
                    .pickerStyle(.segmented)
                    .frame(height: 30)

                    TextField("input", value: $input, format:.number)
                        .keyboardType(.numberPad)

                } header: {
                    Text("Input")
                }

                //output
                Section{

                    Picker("UNIT", selection: $outputUnitIndex) {
                        ForEach(units, id: \.self) {
                            Text("\($0)")
                        }
                    }
                    .pickerStyle(.segmented)
                    .frame(height: 30)

                    Text(outcome, format:.number)
                } header: {
                    Text("output")
                }  

            }.navigationTitle("length conversion")
        }
    }
}

2      

Think this one might for @Obelix who would probably give a better answer

Question to ask

  1. Does it work? - Yes this work and does what you want.
  2. Can it be Improved - Most code can.
  3. I must admit that this was a different way on doing the conversion then I had seen! Nice one

The only thing is that you are using a lot of strings, may think about using an enum instead.

Advantages

  1. Less likely to make typo mistakes
  2. Use CaseIterable in the ForEach
  3. switch is exhaustive, no need for default:

If you want to change then have a go. Will paste mine in the next post if you want to have a look.

3      

struct ContentView: View {
    enum Unit: String, CaseIterable {
        case m, km, ft, yds, mi

        var unitType: String {
            self.rawValue.uppercased()
        }
    }
    @State private var input = 0.0
    @State private var output = 0.0
    @State private var inputUnitIndex = Unit.m
    @State private var outputUnitIndex = Unit.m

    let mConvert: [Unit: Double] = [.m: 1, .km: 0.001, .ft: 3.280839, .yds: 1.93613, .mi: 0.0006213]
    let kmConvert: [Unit: Double] = [.m: 1000, .km: 1, .ft: 3280.839, .yds: 1936.13, .mi: 0.6213]
    let ftConvert: [Unit: Double] = [.m: 0.3048, .km: 0.0003048, .ft: 1, .yds: 0.3333333, .mi: 0.0001893939]
    let ydConvert: [Unit: Double] = [.m: 0.9144, .km: 0.0009144, .ft: 3, .yds: 1, .mi: 0.0005681818]
    let miConvert: [Unit: Double] = [.m: 1609.344, .km: 1.609344, .ft: 5280, .yds: 1760, .mi: 1]

    var outcome: Double {
        var outcomeTotal = 0.0
        switch inputUnitIndex {
        case .m:
            outcomeTotal = (mConvert[outputUnitIndex] ?? 0) * input
        case .km:
            outcomeTotal = (kmConvert[outputUnitIndex] ?? 0) * input
        case .ft:
            outcomeTotal = (ftConvert[outputUnitIndex] ?? 0) * input
        case .yds:
            outcomeTotal = (ydConvert[outputUnitIndex] ?? 0) * input
        case .mi:
            outcomeTotal = (miConvert[outputUnitIndex] ?? 0) * input
        }
        return outcomeTotal
    }

    var body: some View {

        NavigationStack{
            Form {

                //input
                Section {
                    Picker("UNIT", selection: $inputUnitIndex) {
                        ForEach(Unit.allCases, id: \.self) {
                            Text("\($0.unitType)")
                        }
                    }
                    .pickerStyle(.segmented)
                    .frame(height: 30)

                    TextField("input", value: $input, format:.number)
                        .keyboardType(.numberPad)

                } header: {
                    Text("Input")
                }

                //output
                Section{

                    Picker("UNIT", selection: $outputUnitIndex) {
                        ForEach(Unit.allCases, id: \.self) {
                            Text("\($0.unitType)")
                        }
                    }
                    .pickerStyle(.segmented)
                    .frame(height: 30)

                    Text(outcome, format:.number)
                } header: {
                    Text("Output")
                }

            }.navigationTitle("Length Conversion")
        }
    }
}

3      

Based on the Dimension class and UnitLength subclass.

struct ContentView: View {

    @State private var inputValue = 1.0
    @State private var inputUnit = UnitLength.meters
    @State private var outputUnit = UnitLength.meters

    let unitTypes = [UnitLength.meters, UnitLength.kilometers, UnitLength.feet, UnitLength.yards, UnitLength.miles]

    var body: some View {

        NavigationStack{
            Form {

                Section {
                    TextField("From amount", value: $inputValue, format: .number)
                        .keyboardType(.decimalPad)

                    Picker("Convert from", selection: $inputUnit) {
                        ForEach(unitTypes, id: \.self) {
                            Text("\($0.symbol)")
                        }
                    }
                    .pickerStyle(SegmentedPickerStyle())
                    .padding(.horizontal)
                } header: {
                    Text("Convert")
                }

                Section {
                    Text("\(Measurement(value: inputValue, unit: inputUnit).converted(to: outputUnit).value) \(outputUnit.symbol)")

                    Picker("Convert to", selection: $outputUnit) {
                        ForEach(unitTypes, id: \.self) {
                            Text("\($0.symbol)")
                        }
                    }
                    .pickerStyle(SegmentedPickerStyle())
                    .padding(.horizontal)
                } header: {
                    Text("Converted to")
                }
            }.navigationTitle("Length Conversion")
        }
    }
}

3      

Thank you both @NigelGee and @Greenamberred for the enlightment! I'm really grateful for the new knowledge, might take a little time to sink in as both CaseIterable and Dimension are new to me. @NigelGee as you mentioned, can't help curious how typical solution for this challenge looks like now :) anyhow, thanks for the kind word.

2      

BUILD THE ULTIMATE PORTFOLIO APP Most Swift tutorials help you solve one specific problem, but in my Ultimate Portfolio App series I show you how to get all the best practices into a single app: architecture, testing, performance, accessibility, localization, project organization, and so much more, all while building a SwiftUI app that works on iOS, macOS and watchOS.

Get it on Hacking with Swift+

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

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

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.