Hi. I have a button that triggers a request to a webservice:
struct ContentView: View {
@StateObject private var state: State = State()
var body: some View {
VStack {
Button("Request", action: { makeRequest() })
Text(state.response)
}
}
private func makeRequest() {
URLSession.shared.dataTask(with: URL(string: "https://my-json-server.typicode.com/typicode/demo/posts/1")!, completionHandler: { data, _, _ in
state.response = String(bytes: data!, encoding: .utf8)!
})
.resume()
}
}
and an ObservableObject
to store the response in:
class State: ObservableObject {
@Published var response: String = ""
}
.
It seems to workd, but, I get the error message
[SwiftUI] Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates.
So I was wondering if this is the correct way to store the responses of HTTP requests in a StateObject
. I also couldn't find anything about receive(on:)
.
Hi, based on the code you shared I would change two things. If the class contains nothing but a single @Published variable I would just declare a single variable in your ContentView:
struct ContentView: View {
@State private var response: String = ""
...}
And to get rid of the error you have to publish the changes on the main thread(the error warns you because a data task is running on a background thread and also completes on one and therefore any changes you want to display need to be on the main thread).
private func makeRequest() {
URLSession.shared.dataTask(with: URL(string: "https://my-json-server.typicode.com/typicode/demo/posts/1")!, completionHandler: { data, _, _ in
DispatchQueue.main.async{
self.response = String(bytes: data!, encoding: .utf8)!
}
})
.resume()
}
The first part with the class is optional but there is no need for a separate class with a single value :)
Take care David