Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI Optional TextField

Tags:

swiftui

Can SwiftUI Text Fields work with optional Bindings? Currently this code:

struct SOTestView : View {
    @State var test: String? = "Test"

    var body: some View {
        TextField($test)
    }
}

produces the following error:

Cannot convert value of type 'Binding< String?>' to expected argument type 'Binding< String>'

Is there any way around this? Using Optionals in data models is a very common pattern - in fact it's the default in Core Data so it seems strange that SwiftUI wouldn't support them

like image 815
Brandon Bradley Avatar asked Jul 13 '19 18:07

Brandon Bradley


2 Answers

You can add this operator overload, then it works as naturally as if it wasn't a Binding.

func ??<T>(lhs: Binding<Optional<T>>, rhs: T) -> Binding<T> {
    Binding(
        get: { lhs.wrappedValue ?? rhs },
        set: { lhs.wrappedValue = $0 }
    )
}

This creates a Binding that returns the left side of the operator's value if it's not nil, otherwise it returns the default value from the right side.

When setting it only sets lhs value, and ignores anything to do with the right hand side.

It can be used like this:

TextField("", text: $test ?? "default value")
like image 82
Jonathan. Avatar answered Nov 16 '22 07:11

Jonathan.


Ultimately the API doesn't allow this - but there is a very simple and versatile workaround:

extension Optional where Wrapped == String {
    var _bound: String? {
        get {
            return self
        }
        set {
            self = newValue
        }
    }
    public var bound: String {
        get {
            return _bound ?? ""
        }
        set {
            _bound = newValue.isEmpty ? nil : newValue
        }
    }
}

This allows you to keep the optional while making it compatible with Bindings:

TextField($test.bound)
like image 54
Brandon Bradley Avatar answered Nov 16 '22 07:11

Brandon Bradley