10

I am working on a MacOS Swift project (with SwiftUI), and I am having trouble with updating a text label as an event happens.

struct ContentView: View {
    @State var now = globalString.stringy
    var body: some View {
        VStack {
            Text(now)
            .frame(maxWidth: .infinity, maxHeight: .infinity)
        }.onAppear {
             k.start()

        }

    }

}

struct globalString {
    static var stringy = ""
    static var temperature = 0.0
}

The variable now above refers a global variable in a struct that is being changed while the program is running (in a different class that is not referred to in this code), but the changes to the variable will not show up in the text label.

How can I make a variable that is shared between this view and that class, while still having my view update when there is a change in the variable? The changes made to the variable are in a separate file.

I tried using an observable object and an environment object but neither seemed to work.

If anyone could help, I would greatly appreciate it. Thanks!

makertech81
  • 898
  • 2
  • 7
  • 20

1 Answers1

12

To make changes in a SwiftUI view below iOS 17, as it is a static element because of its struct declaration, your object GlobalString must conform to a StateObject to be able to make changes in real-time to a view, and its variables must conform to @Published.

As for SwiftUI view for iOS 17+, you can use the @Observable macro and declare your object as a @State value only.

iOS 17-

class GlobalString: ObservableObject {
  @Published var stringy = ""
  @Published var temperature = 0.0
}

struct ContentView: View {

  @StateObject var globalString = GlobalString()

  var body: some View {
    VStack {
      Text(globalString.stringy)
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
    .onAppear { k.start() }
  }
}

iOS 17+

import Observation

@Observable class GlobalString {
  var stringy = ""
  var temperature = 0.0
}

struct ContentView: View {

  @State var globalString = GlobalString()

  var body: some View {
    VStack {
      Text(globalString.stringy)
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
    .onAppear { k.start() }
  }
}
Roland Lariotte
  • 2,606
  • 1
  • 16
  • 40
  • As I mentioned in the question, I had tried this, however I could not access the variables in non-SwiftUI classes. Is this possible to do? I have a class in another file--that isn't named in the code for the view--that changes a string variable each time a function happens. When it updates this variable, I want the variable to show on the view. – makertech81 Apr 29 '20 at 13:03
  • Is your other class a UiViewController? Is it in a ViewRepresentable? Can you share it, because without the code it is hard to see where it is blocked up. – Roland Lariotte Apr 29 '20 at 17:02
  • I am curious about this too. It looks like the code in ContentView is returning an instance of GlobalString. How can other modules update "stringy" and "temperature"? It seems like ObservableObject by definition needs to be global, i.e. the @Published prefix must denote "class", is this correct? – svenyonson Nov 15 '20 at 00:54
  • @Published is from the Combine framework. With this, you can use your variable "temperature", for example, in a reactive programming way. Which means you can call it and update it from anywhere in the code using Combine. – Roland Lariotte Nov 15 '20 at 15:23