Ich lese aus einem XML-Feed, um eine TableView aufzufüllen, und ich verwende NSXMLParser zum Parsen der XML. Alles funktioniert gut, wenn ich die Daten zum ersten Mal analysiere und die Tabelle wie erwartet ausgefüllt wird. Ich stelle dann einen Timer ein, um die Daten vom Server regelmäßig zu aktualisieren. Wenn der Timer ausgelöst wird, verwende ich genau die gleiche Methode, um den gleichen XML-Feed ein weiteres Mal zu analysieren, und dann schlägt es immer fehl: parser.parse() gibt false zurück, aber es werden keine Fehler gemeldet. Ich kann die Zeilennummer und Spalte bekommen, wo es fehlschlägt, aber die Daten sind oft nicht anders als es war das erste Mal, als es die XML analysiert (und es zu dieser Zeit funktionierte).NSXMLParser parse() funktioniert nur einmal
Ich erkläre den Parser in meinem Tableviewcontroller:
var parser = NSXMLParser()
In ViewDidLoad ich konfigurieren:
let url: String = "http://www.deltatao.com/clanlord/status/cldata.xml"
let urlToSend: NSURL = NSURL(string: url)!
parser = NSXMLParser(contentsOfURL: urlToSend)!
parser.delegate = self
In ViewWillAppear nenne ich es und stellen Sie den Timer:
parseClanlordInformation()
// this will remove the previous timer
timer?.invalidate()
// now start a timer to regularly update the data from the server
startTimer()
Und hier ist die Funktion, die parse() aufrufen:
func parseClanlordInformation() {
// reset players list
players.removeAll()
// Stop the previous parsing operation in case it was still running
parser.abortParsing()
// rebuild the list from scratch
let success: Bool = parser.parse()
if !success {
let error = parser.parserError
let line = parser.lineNumber
let col = parser.columnNumber
print("XML parsing failed at \(line):\(col): \(error?.localizedDescription)")
print(players.count)
}
if parser.parserError != nil {
print("Error: parse failure!")
print(parser.parserError)
}
myTableView.reloadData()
}
Und der Timer ruft die gleiche Funktion:
func startTimer() {
timer = NSTimer.scheduledTimerWithTimeInterval(updateInterval, target: self, selector: #selector(TableViewController.parseClanlordInformation), userInfo: nil, repeats: true)
}
Und die XML-Parser Delegierten wie folgt aufgebaut sind:
func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
currentElement = elementName
if elementName=="exile" || elementName=="race" || elementName=="name" || elementName=="sex" || elementName=="profession" || elementName=="clan" {
if elementName == "exile" {
foundNewPlayer = true
currentPlayer.reset()
}
passData = true
}
}
func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
currentElement = ""
if elementName=="exile" || elementName=="race" || elementName=="name" || elementName=="cost" || elementName=="description" {
if elementName == "exile" {
foundNewPlayer=false
players.append(currentPlayer)
}
passData=false
}
}
func parser(parser: NSXMLParser, foundCharacters string: String) {
if foundNewPlayer {
switch currentElement {
case "name":
currentPlayer.name = string
case "race":
var race: String
if string == "of the People" {
race = "Fen'neko"
} else {
race = String(string.characters.dropFirst(2))
}
currentPlayer.race = race
case "sex":
currentPlayer.genre = string
case "profession":
let prof = String(string.characters.dropFirst(2))
currentPlayer.profession = prof
case "clan":
currentPlayer.clan = string
default: break
}
}
}
func parser(parser: NSXMLParser, parseErrorOccurred parseError: NSError) {
print(parseError.description)
NSLog("failure error: %@", parseError)
}
Wenn ich die App die Tabelle ausführen füllt mit die Daten normalerweise, dann, wenn die erste Aktualisierung ausgelöst wird parser.parse() gibt in Zeile 80, Spalte 1 oder in der Umgebung false zurück.
Warum funktioniert es nur einmal? Gibt es einen Reset, den ich tun sollte, den ich vergessen habe?
Danke für jede Hilfe.
FYI - Sie müssen Ihren Code wirklich umgestalten, damit der Remote-Datenzugriff und das XML-Parsing auf einem Hintergrundthread ausgeführt werden. – rmaddy
Ich stimme einer Netzwerkanfrage und der Empfehlung zu, einen neuen 'NSXMLParser' für jede Analyse zu instanziieren. Nehmen wir einmal an, dass der Inhalt eines bestimmten Elements in einem einzigen Aufruf von 'foundCharacters' zurückgegeben wird. Die gesamte Logik in 'foundCharacters' gehört zu' didEndElement'. 'didStartElement' sollte eine String-Variable initialisieren,' foundCharacters' sollte nur an diese Zeichenkette angehängt werden, und 'didEndElement' sollte dann die gesamte Logik ausführen, die die Zeichenkette interpretiert und darauf reagiert. – Rob
Vielen Dank für die Kommentare. Ich werde das in einen Hintergrund-Thread einfügen und meine Logik in didEndElement einfügen, wie Sie es vorschlagen. Sehr informativ, schätze ich! –