Hello,
I've been struggling with Measurements when used in SwiftUI. I want to be able to convert measurements on the fly, but only the first conversion is working. All subsequent ones fail. I've managed to narrow it down to a reproducible test case.
First, a quick check to see that Foundation works:
// Let’s check that conversion is possible, and works.
var test = Measurement<UnitLength>(value: 13.37, unit: .meters)
print("Original value: \(test.formatted(.measurement(width: .abbreviated, usage: .asProvided, numberFormatStyle: .number)))")
// prints: Original value: 13.37 m
test.convert(to: .centimeters)
print("In centimeters: \(test.formatted(.measurement(width: .abbreviated, usage: .asProvided, numberFormatStyle: .number)))")
// prints: In centimeters: 1,337 cm
test.convert(to: .kilometers)
print("In kilometers: \(test.formatted(.measurement(width: .abbreviated, usage: .asProvided, numberFormatStyle: .number)))")
// prints: In kilometers: 0.01337 km
test.convert(to: .meters)
print("Back to meters: \(test.formatted(.measurement(width: .abbreviated, usage: .asProvided, numberFormatStyle: .number)))")
// prints: Back to meters: 13.37 m
Okay, so it works on the Foundation level. I can convert measurements back and forth, many times.
Now run this ContentView below, and click/tap any button. First time will succeed, further times will fail.
struct ContentView: View {
@State var distance = Measurement<UnitLength>(value: 13.37, unit: .meters)
var body: some View {
VStack {
Text("Distance = \(distance.formatted(.measurement(width: .abbreviated, usage: .asProvided, numberFormatStyle: .number)))")
Button("Convert to cm") { print("Convert to cm"); distance.convert(to: .centimeters) }
Button("Convert to m") { print("Convert to m"); distance.convert(to: .meters) }
Button("Convert to km") { print("Convert to km"); distance.convert(to: .kilometers) }
}
.onChange(of: distance, perform: { _ in
print("→ new distance = \(distance.formatted(.measurement(width: .abbreviated, usage: .asProvided, numberFormatStyle: .number)))")
})
.frame(minWidth: 300)
.padding()
}
}
Replacing distance.convert()
with distance = distance.converted()
does not help.
This is reproducible both on macOS and iOS.
Why on Earth does the first conversion succeed, then all subsequent ones fail? The onChange
isn't even triggered.
// Edit: I'm on Xcode 13.3, macOS 12.3, iOS 15.4