75948

Unable to update/modify SwiftUI View's @state var

<h3>Question</h3>

I'm unable to update the ExampleView's message var even though I can see updateMessage() is being called. Here is my simplified/convoluted SwiftUI example of Playground code that isn't working. The message var does not get updated when called in updateMessage(). As a result, the UI Text() is not updated either.

Why is the @State var message not updating? What is the correct way to update it?

import SwiftUI import PlaygroundSupport struct ContentView: View { let coloredLabel = ExampleView() var body: some View { VStack { coloredLabel .foregroundColor(Color.red) .padding() Button(action: { self.coloredLabel.updateMessage() }) { Text("Press me") } } } } struct ExampleView: View { @State private var message: String = "Hello" var body: some View { Text(self.message) } func updateMessage() { print("updateMessage ran") // this prints self.message = "Updated" } } PlaygroundPage.current.setLiveView(ContentView())
<h3>Answer1:</h3>

You should only change State of a view Inside it's own body block. If you need to change it from a parent view, you may want to pass the value to it from parent and make it Binding instead.

struct ContentView: View { @State private var message = "Hello" var body: some View { VStack { ExampleView(message: $message) .foregroundColor(Color.red) .padding() Button("Press me") { self.message = "Updated" } } } } struct ExampleView: View { @Binding var message: String var body: some View { Text(message) } } <hr />

If you need to encapsulate messages inside the ExampleView, you can use a Bool (or an enum or etc) instead:

struct ContentView: View { @State private var updated = false var body: some View { VStack { ExampleView(isUpdated: $updated) .foregroundColor(Color.red) .padding() Button("Press me") { self.updated = true } } } } struct ExampleView: View { @Binding var isUpdated: Bool private var message: String { isUpdated ? "Updated" : "Hello" } var body: some View { Text(message) } }
<h3>Answer2:</h3>

actually, the variable does get updated, but your Content view doesn't get informed about it. This is what happens:

<ul><li>ContentView gets called, it initializes <i>coloredLabel</i> with an <i>ExampleView</i></li> <li>you press the button in ContentView</li> <li>self.coloredLabel.updateMessage() get's called</li> <li>the message is printed</li> <li>the variable self.coloredLabel.message is modified</li> <li>ContentView does not get redrawn, as it isn't notified about the change</li> <li>more specifically, <i>coloredLabel</i> inside your Stack doesn't get updated</li> </ul>

now, you have different options: @State, @Binding and @PublishedObject, @ObservedObject. You need one of these Publishers, so your view actually notices that it needs to do something.

Either you draw a new ExampleView every time you press the button, in this case you can use a @State variable in ContentView:

struct ContentView: View { @State private var string = "Hello" var body: some View { VStack { ExampleView(message: string) .foregroundColor(Color.red) .padding() Button(action: { self.string = "Updated" }) { Text("Press me") } } } } struct ExampleView: View { var message: String var body: some View { Text(self.message) } }

which is probably not what you want.

Next, you can use <i>@Binding</i> which was already suggested.

And last, you can use <i>ObservableObject @ObservedObject, @Published</i>

class ExampleState: ObservableObject { @Published var message: String = "Hello" func update() { message = "Updated" } } struct ContentView: View { @ObservedObject var state = ExampleState() var body: some View { VStack { ExampleView(state: state) .foregroundColor(Color.red) .padding() Button(action: { self.state.update() }) { Text("Press me") } } } } struct ExampleView: View { @ObservedObject var state: ExampleState var body: some View { Text(state.message) } }

what this says is: class ExampleState: ObservableObject - this class has published variables that can be observed

to resume (that's how I understand it):

<ul><li>"Hey, ContentView and ExampleView: if state.message (any value that state publishes) changes, you need to redraw your body"</li> <li>"And ExampleState: after updating your message variable, publish the new value!"</li> </ul>

lastly - for completion - there is @EnvironmentObject, as well, that way you'd only have to pass the variable to the top-views and everything down the view hierarchy would inherit it.


<h3>Answer3:</h3>

One of the solutions that should work, but as guys say, you can work with @Binding

struct ExampleView: View { var message: String = "Hello" var body: some View { Text(self.message) } mutating func updateMessage() { print("updateMessage ran") message = "Updated" } }

来源:https://stackoverflow.com/questions/59783686/unable-to-update-modify-swiftui-views-state-var

Recommend

  • making an array of bigInteger of size biginteger in java
  • Firebase Database OutofMemory Error
  • How to add an Auth Token in every request using AFIncrementalStore?
  • JQuery UI Datepicker Disbale Next Day After 12pm
  • Mapping google maps coordinate from a javascript variable
  • Batch script read a file that's continously written
  • Docker build error: “could not connect to server” (behind proxy)
  • can I build CMakeLists.txt from a set of smaller files (to improve the readability and maintainabili
  • autotest on ubuntu does nothing
  • App crashes when switching to landscape layout
  • Refresh JSF component after custom javascript Ajax call
  • How to debug iBeacons and Passbook
  • How do you run a synchronous timer in C#?
  • Smarter Removing Unnecessary WhiteSpace CSV
  • Tkinter tkMessageBox disables Tkinter key bindings
  • In metro, get all inherited classes of an (abstract) class?
  • Please update your Node runtime to version >=0.12.x
  • Android studio import problems. (Apktool)
  • How to find angle formed by the blades of a wind turbine with respect to a horizontal imaginary axis
  • How to display converted time zones in a 'generic week' (Sunday thru Saturday)?
  • Use AutoIt with java applications
  • How to select multiple items from a List view - JavaFX 8
  • How to make Rss News Reader application in android …? [closed]
  • Regex not working in java 1.5
  • xpath assertion failure with dynamic xpath
  • how to run a different select statement based on condition in Hive SQL
  • Tensorflow Dataset API restore Iterator after completing one epoch
  • Dynamic XML Schema Validates Subsection of Document
  • How to define something in JavaScript [closed]
  • LinkedIn API: Access Denied when getting Access Token
  • Neo4j…how to get a visual representation of my data?
  • read part of h5 dataset python
  • Comma decimal separator is ignored by ASP.NET MVC model binder
  • Bitrate JWplayer
  • How to call different template for different category archive page in woocommerce
  • Accessing Arguments, Workflow Variables from custom activities
  • Firebase: How to read from external DB?
  • Write to .csv file with PHP (Commas in Data Error)
  • convert json to excel in java
  • ARKit code issue {unknown error -1=ffffffffffffffff error: Task failed with exit 1}