TransWikia.com

Units and Measurements in Swift

Stack Overflow Asked by Tick_hoges on January 3, 2021

I am trying to make a measurement entry keyboard class that has a text field for the value, and a picker for the unit.

I am having trouble using the Measurement type because of its generic behaviour.

I would like my class to return a new Measurement instance based on the initial value, but allowing the user to change the unit without necessarily converting it. I get the error "Cannot convert value of type ‘Unit’ to expected argument type ‘T’" on the line where I am initialising meas with a value, and a unit of a different type.

Also, is there an way to iterate through the built-in sub units of a Dimension Type? i.e get all the sub units of UnitPressure for example.

If someone could just point me to an answer about similar generic behaviour, that would be much appreciated.

class MeasurementPicker<T : Dimension> {
    
    init(initialUnit: Measurement<T>) {
        self.initUnit = initialUnit
    }
    
    var initUnit: Measurement<T>
    
    func getUnitList() -> [Unit]? {
        switch initUnit.unit.self {
        case is UnitPressure:
            let retUnits: [Unit]? = [
                UnitPressure.bars,
                UnitPressure.gigapascals,
                UnitPressure.hectopascals,
                UnitPressure.inchesOfMercury,
                UnitPressure.kilopascals,
                UnitPressure.megapascals,
                UnitPressure.millibars,
                UnitPressure.millimetersOfMercury,
                UnitPressure.newtonsPerMetersSquared,
                UnitPressure.poundsForcePerSquareInch
            ]
            return retUnits
        default:
            return nil
        }
    }
    
    func getNewType(index: Int) -> Measurement<T> {
        let myNewUnit : Unit = getUnitList()![index]
        var meas = Measurement<T>.init(value: 6, unit: myNewUnit)

    }
    
}

let x = Measurement(value: 5.5, unit: UnitPressure.kilopascals)
let y = MeasurementPicker<UnitPressure>(initialUnit: x)
let z = y.getNewType(index: 0)
print(z.unit.symbol)

One Answer

There is no need to create a generic class. Just create a unit or dimension property. And in your method getNewType return Measurement<Unit> or just the unit or the dimension. You can also just use a subscript to get the dimension from your list:

class MeasurementPicker {
    init(dimension: Dimension) { self.dimension = dimension }
    var dimension: Dimension
    var list: [Dimension] {
        switch dimension.self {
        case is UnitPressure:
            return [UnitPressure.bars,
                    UnitPressure.gigapascals,
                    UnitPressure.hectopascals,
                    UnitPressure.inchesOfMercury,
                    UnitPressure.kilopascals,
                    UnitPressure.megapascals,
                    UnitPressure.millibars,
                    UnitPressure.millimetersOfMercury,
                    UnitPressure.newtonsPerMetersSquared,
                    UnitPressure.poundsForcePerSquareInch]
        default: return []
        }
    }

}

Usage:

let y = MeasurementPicker(dimension: UnitPressure.kilopascals)
let z = y.list[0]
print(z.symbol)   // "barn"

Correct answer by Leo Dabus on January 3, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP