'SwiftUI TextField with formatter broken when built with Xcode 13.3?

It looks like Xcode 13.3 broke the TextField with formatter. In example below the Text should show the value entered in the TextField, which works fine when built with Xcode 13.2.1 (downgraded again to test) but with Xcode 13.3 the TextField does not update its binding value.

struct ContentView: View {

    @State var value: Float?

    let decimalFormatter: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal
        formatter.maximumFractionDigits = 3
        return formatter
    }()

    var body: some View {
        VStack {
            TextField("some float", value: $value, formatter: decimalFormatter)
                .multilineTextAlignment(.center)
                .keyboardType(.decimalPad)
            Text("Value: \(value != nil ? String(value!) : "nil")")
        }
    }
    
}
  • is my code somehow flawed because it stopped working with Xcode 13.3 or is this a bug with Xcode 13.3?
  • any idea how to fix my code or workaround that bug in Xcode 13.3? - my current workaround is a downgrade to Xcode 13.2.1


Solution 1:[1]

Found a different API that does what I expected with optionals: https://developer.apple.com/documentation/swiftui/textfield/init(_:value:format:prompt:)-6ug7k

TextField("some float", value: $value, format: FloatingPointFormatStyle.number)

Although this does not explain why it previously worked with a Formatter and stopped working with Xcode 13.3, at least this API seems to be specific for optional values.

Limiting fraction digits to 3 also works, it just is not applied instantly during editing but afterwards on focus change.

TextField("some float", value: $value, format: FloatingPointFormatStyle.number
.precision(NumberFormatStyleConfiguration.Precision.fractionLength(0...3)))

Solution 2:[2]

Corrected code sample, using the method from @harp's answer. This only works on iOS 15+.

TextField("some float",
           value: $value,
           format: .currency(code: "USD"))
   .onChange(of: value) { newValue in
           print ("value is \(newValue)")
       }

Another example of a format. Here using one of the Instance Methods from the Apple docs on FloatingPointFormatStyle:

TextField("some float",
           value: $value,
           format: FloatingPointFormatStyle().decimalSeparator(strategy: .automatic))

More info on this method is in the Apple docs for TextField.init(_:value:format:prompt:)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 spnkr