Hier zeige ich Dir, wie du mit Swift UI eine Liste generierst. Zuerst laden wir ein XML-File aus dem Web. Dann durchlaufen wir das Array und füllen eine neue DataSource Class mit einem identifiable struct. Wir achten darauf, dass wir nicht @State verwenden, sondern @ObservedObject. Die DataSource class hat den Typ ObservableObject. Für die Liste gibt es ein eigenes Struct, das macht die ganze sache übersichtlicher. Ich selber habe den Fehler als Swift UI Neuling hier @State zu verwenden. Bei dem Versuch die Datenquelle zu füllen, bekam ich keine Fehlermeldung, aber die Anzahl der Datensätze aus dem gelesenen XML-File blieb schlichtweg 0.
Hierfür ein Swift-File anlegen. Das ist die Klasse um XML zu parsen.// // XMLParser.swift // Listory // // Created by T. Stephan on 15.02.20. // Copyright © 2020 eCommerce - Tobias Stephan. All rights reserved. // import UIKit import Foundation class ListoryXMLParser: UIViewController, XMLParserDelegate { var parser = XMLParser() let recordKey = "export" var dictionaryKeys = [String]() //"ASIN","Titel","Hersteller","Marke","BuyBoxPreis","Logdatum","Gesamtangebote","Bulletpoints"] // a few variables to hold the results as we parse the XML public var results: [[String: String]]? = [[String: String]]() // the whole array of dictionaries var currentDictionary: [String: String]! // the current dictionary var currentValue: String? let defaults = UserDefaults.standard func beginParsing(tablename: String,criterion: String){ let sASIN = "" beginParsing(tablename: tablename, criterion: criterion, asin: sASIN) } func beginParsing(tablename: String,criterion: String,asin: String) { results?.removeAll() //posts = [] //let defaults = UserDefaults.standard var sHostname = "https://www.hostname.de/" if (defaults.string(forKey: "httpHostname") != nil){ sHostname = defaults.string(forKey: "httpHostname")! } var sUrl = sHostname + "/exportxml.aspx?table=" + tablename + "&criterion=" + criterion if asin != "" { sUrl = sUrl + "&asin=" + asin } if (defaults.string(forKey: "fcm") != nil){ sUrl = sUrl + "&token=" + defaults.string(forKey: "fcm")! } parser = XMLParser(contentsOf:(NSURL(string: sUrl))! as URL)! parser.delegate = self parser.parse() } func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { if elementName == recordKey { currentDictionary = [String : String]() } else if dictionaryKeys.contains(elementName) { currentValue = String() } } func parser(_ parser: XMLParser, foundCharacters string: String) { currentValue? += string } func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { if elementName == recordKey { results?.append(currentDictionary) currentDictionary = nil } else if dictionaryKeys.contains(elementName) { currentDictionary[elementName] = currentValue currentValue = nil } } func parserDidStartDocument(_ parser: XMLParser) { //results = [[:]] } func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) { print(parseError) } }
Dann legen wir noch ein SwiftUI File ein und definieren hier das struct für die Datenquelle.
Grundlage für die Datenquelle:import SwiftUI struct oListEntryFields: Identifiable { var id = UUID() var rowID : Int64 var ListKey : String var ListenGruppenKey : String var ListenKeyView : String var Caption: String }
Hier bewegen wir uns nun im ContentView.swift File. Hier findet man dann auch die Klasse für die Datenquelle.
import SwiftUI import Combine class ListDataSource: ObservableObject { var ListOfListEntries = [oListEntryFields]() let oListoryParser = ListoryXMLParser() init() { oListoryParser.dictionaryKeys.removeAll() oListoryParser.dictionaryKeys.append("ID"); oListoryParser.dictionaryKeys.append("ListenKey"); oListoryParser.dictionaryKeys.append("ListenGruppenKey"); oListoryParser.dictionaryKeys.append("ListenKeyView"); oListoryParser.dictionaryKeys.append("Bezeichnung"); oListoryParser.dictionaryKeys.append("Aenderungsdatum"); oListoryParser.dictionaryKeys.append("Erstanlagedatum"); oListoryParser.dictionaryKeys.append("Archiviert"); oListoryParser.dictionaryKeys.append("Wiedervorlage"); oListoryParser.beginParsing(tablename: "key", criterion: "bsCQ2ivUHXOyk") var iRow = -1 for s in oListoryParser.results! { iRow += 1 let rowID = Int64(s["ID"]!) let ListEntry = oListEntryFields(rowID: rowID!, ListKey: s["ListenKey"]!, ListenGruppenKey: s["ListenGruppenKey"]!, ListenKeyView: s["ListenKeyView"]!, Caption: s["Bezeichnung"]!) //LoadListData.append(ListEntry) ListOfListEntries.append(ListEntry) } } } public struct ContentView: View { @State var selection: Int = 0 let defaults = UserDefaults.standard public var body: some View { TabView(selection: $selection){ VStack{ ListoryListView() } .tabItem { VStack { Image("first") Text("First") } } .tag(0) Text("Second View") .font(.title) .tabItem { VStack { Image("second") Text("Second") } } .tag(1) }.onAppear(){ } } struct ListoryListView: View { @ObservedObject var oListDatasource = ListDataSource() let oListoryParser = ListoryXMLParser() @State var selection = Set() var body: some View { NavigationView { List(){ ForEach(oListDatasource.ListOfListEntries) { item in VStack(alignment: .leading){ Text(item.Caption) } .onTapGesture { print("\(item.Caption)") } .navigationBarTitle(Text("List")) }.onDelete(perform: xdelete) } } } func xdelete(at offsets: IndexSet) { if let first = offsets.first { print("remove \(first)") oListDatasource.ListOfListEntries.remove(at: first) } } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
Über den Autor