URLSession for XMLParser in SwiftUI returning empty or nil

I am attempting to parse XML using an URLSession, XCode 12, SwiftUI but it keeps returning [] or nil. If I print immediately after the parse(see code), all the data is there, but for some reason, it seems to be clearing it all out.

If I try it with a .xml file, the code works fine, so it must be something in my URLSession in a XMLParserDelegate class:
Code Block
class ParseController: NSObject, XMLParserDelegate{
var items: [Item] = []
var itemStore: [Item]?
func loadData() {
let url = URL(string: "website")!
let request=URLRequest(url: url)
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if data == nil {
print("dataTaskWithRequest error: \(String(describing: error?.localizedDescription))")
return
}
let parser = XMLParser(data: data!)
parser.delegate=self
parser.parse()
self.itemStore=self.items
print(self.itemStore)
}
task.resume()
/*
if let path = Bundle.main.url(forResource: "Items", withExtension: "xml") {
if let parser = XMLParser(contentsOf: path) {
parser.delegate = self
parser.parse()
self.itemStore=self.items
}
}
*/
}

And then I call that with a button in my View:
Code Block
struct MyParserView: View {
@State var itemsResult: [Item]?
var body: some View {
if ((itemsResult?.isEmpty) == nil) {
VStack {
Text("Stuff here")
Button(action: {
let parserControl = ParseController()
parserControl.loadData()
itemsResult = parserControl.itemStore
}){
Text("Push")
}
}
}else {
List{
ForEach(itemResult!, id:\.id){item in
Text(item.name)
}
}
}
}
}

Accepted Answer
Your code does not work because it does not handle asynchronous calls properly.

When you call loadData(), the completion handler passed to dataTask (line 9. { (data, response, error) in to line 21 }) is executed after loadData() is finished.

One way of utilizing the result of async calls in SwiftUI is using @Published var in an ObservableObject.

Update your ParseController as follows:
Code Block
class ParseController: NSObject, XMLParserDelegate, ObservableObject { //<-
var items: [Item] = []
@Published var itemStore: [Item]? //<-
func loadData() {
let url = URL(string: "website")!
let request=URLRequest(url: url)
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if let error = error {
print("dataTaskWithRequest error: \(error)")
return
}
guard let data = data else {
print("dataTaskWithRequest data is nil")
return
}
let parser = XMLParser(data: data)
parser.delegate = self
parser.parse()
self.itemStore = self.items
print(self.itemStore)
}
task.resume()
}
//... I assume you are implementing `XMLParserDelegate` methods properly...
}


And use it in a SwiftUI view like this:
Code Block
struct MyParserView: View {
@StateObject var parserControl = ParseController() //<-
var body: some View {
if let itemsResult = parserControl.itemStore, !itemsResult.isEmpty {
List{
ForEach(itemsResult, id:\.id) {item in //<-
Text(item.name)
}
}
} else {
VStack {
Text("Stuff here")
Button(action: {
//Do nothing here //<-
parserControl.loadData()
//Do nothing here //<-
}){
Text("Push")
}
}
}
}
}


This is not tested, so you may need to modify some parts, but please try.
Thanks!
Lost track of the forest through the trees...this was not a XML problem at all!

I used @ObservedObject instead of @State and also had to add a DispatchQueue when updating itemStore.
URLSession for XMLParser in SwiftUI returning empty or nil
 
 
Q