2016-05-18 14 views
1

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.

+0

FYI - Sie müssen Ihren Code wirklich umgestalten, damit der Remote-Datenzugriff und das XML-Parsing auf einem Hintergrundthread ausgeführt werden. – rmaddy

+0

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

+1

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! –

Antwort

0

Ich bin mir ziemlich sicher, dass eine bestimmte Instanz von NSXMLParser nur einmal verwendet werden kann. Erstellen Sie jedes Mal eine neue Instanz, wenn Sie erneut analysieren möchten.

func parseClanlordInformation() { 
    // reset players list 
    players.removeAll() 
    // Stop the previous parsing operation in case it was still running 
    parser.abortParsing() 

    // Setup new parser 
    let url: String = "http://www.deltatao.com/clanlord/status/cldata.xml" 
    let urlToSend: NSURL = NSURL(string: url)! 

    parser = NSXMLParser(contentsOfURL: urlToSend)! 
    parser.delegate = self 

    // 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() 
} 

Dies bedeutet auch Sie den Parser-Setup in viewDidLoad entfernen können.

Verwandte Themen