Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI @Binding update doesn't refresh view

Tags:

I feel like I'm missing something very basic, but this example SwiftUI code will not modify the view (despite the Binding updating) when the button is clicked

Tutorials I have read suggest this is the correct way to use a binding and the view should refresh automatically

import SwiftUI  struct ContentView: View {     @Binding var isSelected: Bool      var body: some View {         Button(action: {             self.isSelected.toggle()         }) {             Text(isSelected ? "Selected" : "Not Selected")         }     } }  struct ContentView_Previews: PreviewProvider {     @State static var selected: Bool = false      static var previews: some View {         ContentView(isSelected: $selected)     } } 
like image 731
simeon Avatar asked Dec 12 '19 06:12

simeon


Video Answer


2 Answers

You have not misunderstood anything. A View using a @Binding will update when the underlying @State change, but the @State must be defined within the view hierarchy. (Else you could bind to a publisher)

Below, I have changed the name of your ContentView to OriginalContentView and then I have defined the @State in the new ContentView that contains your original content view.

import SwiftUI  struct OriginalContentView: View {     @Binding var isSelected: Bool      var body: some View {         Button(action: {             self.isSelected.toggle()         }) {             Text(isSelected ? "Selected" : "Not Selected")         }     } }  struct ContentView: View {     @State private var selected = false      var body: some View {        OriginalContentView(isSelected: $selected)     } }    struct ContentView_Previews: PreviewProvider {     static var previews: some View {         ContentView()     } } 
like image 89
ragnarius Avatar answered Sep 19 '22 12:09

ragnarius


SwiftUI View affects @Binding. @State affects SwiftUI View. @State var affects the view, but to affect another @State it must be used as binding by adding leading $ to value name and it works only inside SwiftUI.

To trigger SwiftUI change from outside, i.e. to deliver/update Image, use Publisher that looks like this:

// Declare publisher in Swift (outside SwiftUI). public let imagePublisher = PassthroughSubject<Image, Never>()      // It must be handled within SwiftUI. struct ContentView: View {     // Declare a @State that updates View.     @State var image: Image = Image(systemName: "photo")     var body: some View {         // Use @State image declaration         // and subscribe this value to publisher "imagePublisher".         image.onReceive(imagePublisher, perform: { (output: Image) in             self.image = output  // Whenever publisher sends new value, old one to be replaced         })     } }  // And this is how to send value to update SwiftUI from Swift: imagePublisher.send(Image(systemName: "photo")) 
like image 22
Niko Avatar answered Sep 21 '22 12:09

Niko