2

Hello i have an issue with the refresh of my view when i toggle a boolean. Here is the code

class MyItem: Identifiable {
   @Published var isActive: Bool
}

struct myView: View {
   @Binding var item: MyItem
   var body: some View {
      HStack {
         Toggle("", isOn: $item.isActive)
         Spacer()
         TextField("", text: item.isActive ? $text : .constant("")) { isFocused in
             guard !isFocused && text.count == 0 else { return }
             item.isActive.toggle
         }
            .background(item.isActive ? Color.white : Color.clear)
      }
   }
}

when i lose my focus and run item.isActive.toggle it change correctly his value, but my Toggle and my TextField doesn't update their UI (the Toggle is still active and the background of the TextField is still white)

Any idea of what i am missing ?

2
  • In context of SwiftUI Published works only in ObservableObject which is wrapped in ObservedObject in view. Find some tutorial by key words. Commented Jun 10, 2022 at 9:31
  • How do you supply the binding from the superview? Commented Jun 10, 2022 at 9:35

1 Answer 1

3

Binding only updates the view when the wrapped value is updated. However, since your wrapped value is a class, not a struct, the view would only be updated if you replaced the instance with another one, not if you updated a property of the instance.

You need to make MyItem conform to ObservableObject and use @ObservedObject or @StateObject on your view, then it will be updated correctly.

class MyItem: ObservableObject {
   @Published var isActive: Bool
}

struct myView: View {
   @ObservedObject private var item: MyItem

   init(item: MyItem) {
       self.item = item
   }

   var body: some View {
      HStack {
         Toggle("", isOn: $item.isActive)
         Spacer()
         TextField("", text: item.isActive ? $text : .constant("")) { isFocused in
             guard !isFocused && text.count == 0 else { return }
             item.isActive.toggle
         }
            .background(item.isActive ? Color.white : Color.clear)
      }
   }
}
Sign up to request clarification or add additional context in comments.

4 Comments

Ok, but i have to keep @Binding private var item: MyItem because myView is used as an item list which will update his parent's viewModel. ForEach($viewModel.items) { $item in MyView(item: $item) }
@user3227545 no, you don't. You can get a Binding from an ObservedObject using the same $ syntax and everything will work perfectly.
After some tests in works just fine. On my parent view my array of item is up to date when i check on click on a button. In addition i am looking for a way to catch update of the item in my parent via the array of item. have you an idea for that ?
@GauthierBeignie you mean you want to update the parent view itself when any item updates? This answer explains how to propagate changes from child ObservableObjects to their parents.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.