My app contains a resource heavy operation that populates an Array based on data pulled from an XML feed. I do not want this operation to lock up the main thread (and the UI when the array is given new data), so it's done in the background.
let dispatchQueue = DispatchQueue(label: "concurrent.queue", qos: .utility, attributes: .concurrent)
class XMLHandler: ObservableObject {
let context: NSManagedObjectContext
@Published var myArray: [CustomObject] = []
init(context: NSManagedObjectContext) {
self.context = context
}
...some code...
func populateArray {
dispatchQueue.async {
...xml parsing happens...
(xmlOutputObject) in
for x in xmlOutputObject {
self.myArray.append(x)
}
}
}
}
Elsewhere, my SwiftUI View uses myArray to populate it's List:
struct MyView: View {
@EnvironmentObject var handler: XMLHandler
var body: some View {
List{
ForEach(handler.myArray) { CustomObject in
... generate rows ...
}
}
}
My error on runtime occurs when my app tries to update @Published var myArray: [CustomObject] = [].
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.
I know this is something to do with adopting Combine, but I honestly have no idea where to start. Any help would be appreciated.
I simply want the following to happen:
- User presses button that initiates the XML data pull that populates myArray
- myArray is populated on background thread, keeping UI responsive
- List in MyView automatically updates upon task completion. At present, I have to navigate away from the view and back again for the List to refresh.