I have a SwiftUI view MainExportMenu
which is controlled by an Export controller
in an event driven app. The UI triggers the Export controller
to create a document, which is done on another thread. Once the document is ready, an event is triggered that calls receive
in the app.
When this happens, I want to update the UI by toggling isReadyForExport
to cause a Spinner
to show.
If I do this directly from the function that the button calls, this works as intended, however if this is done from the event, this results in the UI not being updated. How would an event call update the UI?
Below is my code:
struct MainExportMenu: View {
@StateObject var exportController = ExportController()
var body: some View {
Button(action: {
exportController.generate(IDs: self.IDs, as: self.exportType)
})
if exportController.isReadyForExport {
Spinner()
}
}
}
And controller
class ExportController: ObservableObject {
init() {
app.add(self) //This adds it to the app for the event framework to reference back when it publishes its event. This is retained
}
deinit {
app.remove(self) // removes it's reference from the event framework
}
@Published var isReadyForExport = false {
didSet {
self.objectWillChange.send()
}
}
//This function gets an event from anthother part of the App - this does call successfully but does not update the UI
func receive(_ event: Events.Event) -> Bool {
print("I am here and recieved data") //this is called
self.isReadyForExport = true //does not update the UI but objectWIllChagne.send() is called
return true
}
func generate(IDs exportIds: [UUID], as exportType: ExportType?) {
//self.isReadyForExport = true - THIS WILL WORK - if the call is made here it will work
prepareDocuments(exportIds: exportIds, exportType: exportType) // calls an event that another thread will receive which will result in receive being called
}
}
I have tested the following approaches with no success:
- ensured that the
ExportController
is the same object via a memory address when called from event and UI - ensured that the
ExportController
is on the main thread - Attempted to use
DispatchQueue.main.async { self.isReadyForExport = true }
as suggested here: Update a variable that changes the UI from background thread - SWIFTUI - Using
ObservedObject
instead ofStateObject