My function is used to convert between kilograms and pounds. For some unknown reason, the converted(to:)
method seems to be either returning 0 (which I think is unlikely) or the assignment of the returned value to liftWeight
isn't working.
func convertUnit(liftEvent: LiftEventRepresentable ) -> LiftEventRepresentable {
let unit = liftEvent.liftWeight.unit.symbol
switch unit {
case "kg":
let weight = liftEvent.liftWeight
print("Event weight is \(weight)") // 110.0 kg
let liftWeight = weight.converted(to: .pounds) // this is returning 0 or the assignment isn't working
print("The new weight is \(liftWeight)") 0.0 lb
liftEvent.updateWeightLifted(liftWeight.value)
liftEvent.updateWeightUnit(liftEvent.liftWeight.unit.symbol)
return liftEvent
case "lb":
// I'll finish this case after I get case "kg": working
default:
fatalError("Oops, this should not happen")
}
}
I thought it might be similar to a problem I had in the past which involved trying to assign a Measurement
to an optional but I don't have any optional values in this method so I assume I must be doing something else wrong.
LiftEvent:
extension LiftEvent {
@NSManaged var date: Date
@NSManaged var repetitions: NSNumber
@NSManaged var uid: NSNumber?
@NSManaged var weightLifted: NSNumber
@NSManaged var weightUnit: String
@NSManaged var formula: Formula
@NSManaged var lift: Lift
}
The LiftEventRepresentable protocol is:
@objc protocol LiftEventRepresentable {
var date: Date { get }
var formula: Formula { get }
var repetitions: NSNumber { get set }
var liftWeight: Measurement<UnitMass> { get }
var maxWeight: Double { get }
var lift: Lift { get }
var context: NSManagedObjectContext { get }
var userDidChangeUnits: Bool { get set }
func updateWeightLifted(_ weight: Double)
func updateRepetitions(_ repetitions: Int)
func updateMaxAmount(_ maxAmount: Measurement<UnitMass>) -> ()
func updateLiftEventFormula(_ newFormulaUuid: String) -> ()
func updateLift(_ newLiftUuid: String) -> ()
func updateWeightUnit(_ newUnit: String)
func calculateOneRepMax() -> Measurement<UnitMass>
func updateLiftEventWithFinalValues()
}
Can anyone tell me why liftEvent.liftWeight
is 0.0 lb after the conversion?
EDIT 1: This is how liftEvent.liftWeight
is produced (which I should have included in my question originally). It's a computed property and I've now learning it's what causes the conversion to always return 0):
class LiftEvent: NSManagedObject, LiftEventRepresentable {
var liftWeight: Measurement<UnitMass> {
let defaultUnit = UserDefaults.weightUnit() // returns a string ("kg" or "lb")
let unitSymbol = UnitMass.init(symbol: defaultUnit) // the wrong way
let liftWeight = Measurement<UnitMass>(value: Double(weightLifted), unit: unitSymbol)
return liftWeight
}
EDIT 2: The root problem was, indeed, the liftEvent.liftWeight being invalid.
This is my new code which now works:
var liftWeight: Measurement<UnitMass> {
let defaultUnit = UserDefaults.weightUnit() // returns a string ("kg" or "lb")
let unit: UnitMass
if defaultUnit == "kg" {
unit = UnitMass.kilograms // the right way
} else {
unit = UnitMass.pounds // also the right way
}
let liftWeight = Measurement<UnitMass>(value: Double(weightLifted), unit: unit)
return liftWeight
}
Something is wrong with your Measurement
's unit. It's a UnitMass
so it has the correct dimension, but its converter is missing. This is probably because you created it using something like UnitMass(symbol: "kg")
instead of UnitMass.kilograms
.
// right way
let goodUnit = UnitMass.kilograms
let goodWeight:Measurement = Measurement(value: 110.0, unit: goodUnit)
print("Good pounds: ", goodWeight.converted(to: .pounds)) // 242.508686220216 lb
// wrong way (results in 0.0 output)
let badUnit = UnitMass(symbol: "kg")
let badWeight:Measurement = Measurement(value: 110.0, unit: badUnit)
print("Bad pounds: ", badWeight.converted(to: .pounds)) // 0.0 lb
Creating a unit with UnitMass(symbol: "kg")
is actually valid code, so there's no error. You can use this syntax to create your own mass units with any symbol you want and a custom converter. For some reason the converter:
parameter is optional, so UnitMass(symbol: "kg")
just makes a new mass unit with the symbol "kg" and a default UnitLinearConverter
with a coefficient of 0.
Using UnitMass.kilograms
instead gives you a predefined kilogram unit that's already setup with the correct symbol and converter. Easy mistake to make, especially since there's no error.
I recommend taking a look at where you create liftEvent.liftWeight
, as that is likely where the problem lies.