19
votes

I have a Binding to a Double parameter that is set by a SwiftUI TextField. I use a custom Formatter that converts to and from a Double value. The TextField sends an empty string "" to the Formatter upon editing so the conversion fails and the Double parameter is not updated. The struct is called from a parent View which has a @ObjectBinding parameter and the Double is a parameter of that object.

I am currently using Xcode 11 beta 3 and macOS Catalina Beta 3. The TextField works if the parameter is a String. The problem appears to be that a non-String type, which requires a Formatter fails to properly update the @Binding value.
Here is the Formatter:

public class DoubleFormatter: Formatter {

    override public func string(for obj: Any?) -> String? {
        var retVal: String?
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal

        if let dbl = obj as? Double {
            retVal = formatter.string(from: NSNumber(value: dbl))
        } else {
            retVal = nil
        }

        return retVal
    }

    override public func getObjectValue(_ obj: AutoreleasingUnsafeMutablePointer<AnyObject?>?, for string: String, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool {

        var retVal = true

        if let dbl = Double(string), let objok = obj {
            objok.pointee = dbl as AnyObject?
            retVal = true
        } else {
            retVal = false
        }

        return retVal

    }
}

Here is the SwiftUI View that takes the Double parameter in a TextField

struct HStackTextTextField : View {
    var text: String
    @Binding var value: Double
    @State var valueState: Double

    var body: some View {
        HStack {
            Text("\(value)") //shows the value failing to update 
            TextField("Number", value: $value, formatter: DoubleFormatter()) //Still Fails
            Text("\(valueState)") //shows valueState updating properly
            TextField("Number", value: $valueState, formatter: DoubleFormatter()) //works as expected
        }
    }
}

I expect the TextField value to update when I type, but it does not. When I trace the value in the the Formatter. The string provided to getObjectValue is "" instead of the value in the TextField.

UPDATE: As of catalina/Xcode beta 5, this still appears to be an issue when the View TextField parameter is defined as @Binding and passed to the View. It appears to work as expected if the TextField parameter is defined as @State and is local to the View.

1
Looks like this is still an issue with Xcode 11 GM 2/macOS 10.15 Beta 8Austin
Here we are more than a year later and it still doesn't work.C6Silver

1 Answers

6
votes

I believe this is a bug in SwiftUI. (See my similar question: SwiftUI TextField with formatter not working?)

In beta 2, it didn't work at all. In beta 3, I think you'll find that your result gets passed to your formatter if (and only if) you hit return after typing in the field. Hopefully in beta 4 they'll finish fixing the bug!