How to pass optional binding to a SwiftUI component

Ondrej Kvasnovsky
1 min readDec 21, 2022

--

When we have an optional field in a our model, the SwiftUI will give us the following exception:

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

Have a look at the following code. The description is optional and TextField does not accept Binding<String?> but it expects Binding<String>.

import SwiftUI

struct Book {
var name: String
var description: String?
}

class BookViewModel: ObservableObject {
@Published var book = Book(name: "")
}

struct ContentView: View {

@ObservedObject var vm: BookViewModel = BookViewModel()

var body: some View {
VStack {
TextField("", text: $vm.book.name)
TextField("", text: $vm.book.description)
}
.padding()
}
}

We can implement the following function that will create a new binding that makes sure there is always some value returned.

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

Then we can use ?? where we provide the optional binding on the left side and the default value on the right side.

struct ContentView: View {

@StateObject var vm: BookViewModel = BookViewModel()

var body: some View {
VStack {
TextField("", text: $vm.book.name)
TextField("", text: $vm.book.description ?? "")
}
.padding()
}
}

References and additional reading

--

--

Responses (2)