I have made a SwiftUI app that repeatedly fetches telemetry data to update custom views. The views use a variable stored in an EnvironmentObject.
struct updateEO{
@EnvironmentObject var settings:UserSettings
func pushSettingUpdate(telemetry: TelemetryData) {
settings.info = telemetry
print(settings.info)
}
}
class DownloadTimer : ObservableObject {
var timer : Timer!
let didChange = PassthroughSubject<DownloadTimer,Never>()
@Published var telemetry = TelemetryData()
func start() {
connectToClient()
self.timer?.invalidate()
self.timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) {
_ in
guard let url = URL(string: "http://127.0.0.1:25555/api/telemetry") else {
print("Invalid URL")
return
}
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
if let decodedResponse = try? JSONDecoder().decode(TelemetryData.self, from: data) {
DispatchQueue.main.async {
updateEO().pushSettingUpdate(telemetry: decodedResponse)
}
return
}
}
}.resume()
}
}
}
At runtime, when the telemetry is passed to the pushSettingUpdate(telemetry: decodedResponse)
, the app crashes with an error of 'Fatal error: No ObservableObject of type UserSettings found.'.
I understand I may need to pass the struct the EnvironmentObject but I am not sure on how to do that. Any help would be much appreciated. Thanks! :)
You should use @EnvironmentObject
in your view and pass it down to your model if needed.
Here, struct updateEO
is not a view.
I've created a simpler example to show you how to do this :
class UserSettings: ObservableObject {
@Published var info: String = ""
}
class DownloadTimer: ObservableObject {
var timer : Timer?
func start(settings: UserSettings) {
self.timer?.invalidate()
self.timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { t in
settings.info = t.fireDate.description
}
}
}
And you call start
(with UserSettings
as parameter) when the Text
appears.
struct MyView: View {
@StateObject private let downloadTimer = DownloadTimer()
@EnvironmentObject var settings: UserSettings
var body: some View {
Text(settings.info)
.onAppear {
self.downloadTimer.start(settings: self.settings)
}
}
}
And don't forget to call .environmentObject
function to inject your UserSettings
in SceneDelegate
.
let contentView = MyView().environmentObject(UserSettings())
You should see the text updating as time goes by.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With