Swift – How to assign an optional Binding parameter in SwiftUI

bindingswiftswiftui

I'm trying to build a custom NavBar with some optional Views, like a searchbar (but only if the view needs to display it).

I need to pass some @State properties with @Binding down the views, basically. But I also need them to be Optional parameters.

Here's an example:

struct NavBar: View {
    
    var isSearchable: Bool?
    
    @Binding var searchTxt: String
    @Binding var searchIsOn: Bool
    
    var navBarTitle: String
    var navBarAction: (() -> Void)?
    var navBarImage: String?
    
    init(navBarTitle: String, navBarAction: (() -> Void)? = nil, navBarImage: String? = nil, isSearchable: Bool? = false, searchTxt: (Binding<String>)?, searchIsOn : (Binding<Bool>)?) {
        self.navBarTitle = navBarTitle
        if(navBarAction != nil) {
            self.navBarAction = navBarAction!
        }
        if(navBarImage != nil) {
            self.navBarImage = navBarImage!
        }
        self.isSearchable = isSearchable
        
        self._searchTxt = (searchTxt != nil) ? (searchTxt!).binding : nil
        self._searchIsOn = (searchIsOn != nil) ? (searchIsOn!).binding : nil
        
        assert((navBarAction != nil) ? navBarImage != nil : true)
        assert((isSearchable! == true) ? (searchTxt!.value.count > 0) : true)
    }
// var body ....

}

The properties I'm talking about are searchIsOn and searchTxt.
But doing the assignment self._searchTxt = searchTxt or self._searchIsOn = searchIsOn throws a compile error:

Cannot assign value of type 'Binding?' to type 'Binding'

Do you know how could I resolve this issue?

Or is there a better way to do what I'm trying to do?

Best Answer

@Binding var searchTxt: String?

init(searchTxt: Binding<String?>?) {
    self._searchTxt = searchTxt ?? Binding.constant(nil)
}

Or consider this: TextField("", text: $text ?? "default value")

https://stackoverflow.com/a/61002589/4728060

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