I am trying to create a SwiftUI view that has a @Binding bool to update it’s internal state depending on the value. I want that bool value to be a isEmpty property of a String stored in a @ObservedObject.
I will explain my issue in a reduced example.
Let’s start with a view model:
@MainActor
final class MainViewModel: ObservableObject {
@Published var magicString = ""
init(magicString: String = "") {
self.magicString = magicString
}
}
Then the view that declares the initial binding, I do not want this view to own the data.
struct BoolView: View {
@Binding var active: Bool
var body: some View {
HStack() {
Image(systemName: active ? "checkmark.circle" : "xmark.circle")
.foregroundStyle(active ? .green : .red)
Text("Is magic happening?")
Spacer()
}
}
}
Lastly I want to add this as a subview of "main view" that has the view model:
struct MainView: View {
@ObservedObject var viewModel: MainViewModel
var body: some View {
BoolView(active: Binding<Bool>(get: { // This is what I do not like
!viewModel.magicString.isEmpty
}, set: { _, _ in
}))
}
}
While this works, I would like to avoid creating the new Binding<Bool>.
How can I pass viewModel.magicString.isEmpty to the BoolView active binding?
Maybe I should not be using @Binding property wrapper in BoolView?
>Solution :
If it’s read-only then it doesn’t need to be a binding. The parent is already dependent on the observed object, so this will cause the body of the parent to be rebuilt when the observed object changes.
Just change the property inside BoolView to this:
let active: Bool
and your MainView to this:
struct MainView: View {
@ObservedObject var viewModel: MainViewModel
var body: some View {
BoolView(active: !viewModel.magicString.isEmpty)
}
}