Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

SwiftUI Readonly binding

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:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

@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)
    }
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading