2016-05-18 3 views
1

Я читаю из XML-фида, чтобы заполнить tableView, и я использую NSXMLParser для синтаксического анализа XML. Все работает отлично при первом анализе данных, и я получаю таблицу, заполненную, как я ожидаю. Затем я устанавливаю таймер для регулярного обновления данных с сервера. Когда таймер запускается, я использую тот же самый метод для синтаксического анализа одного и того же XML-фида в другой раз, а затем он всегда терпит неудачу: parser.parse() возвращает false, но сообщений об ошибках не сообщается. Я могу получить номер строки и столбец, где она терпит неудачу, но данные часто не отличаются от того, что это был первый раз, когда он проанализировал XML (и он работал в то время).NSXMLParser parse() работает только один раз

Я объявляю анализатор в моем TableViewController:

var parser = NSXMLParser()

В ViewDidLoad настроить его:

let url: String = "http://www.deltatao.com/clanlord/status/cldata.xml" 

    let urlToSend: NSURL = NSURL(string: url)! 

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

В ViewWillAppear я называю его и установить таймер:

parseClanlordInformation() 
    // this will remove the previous timer 
    timer?.invalidate() 
    // now start a timer to regularly update the data from the server 
    startTimer() 

И вот функция, которая вызывает parse():

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


} 

И таймер вызывает ту же функцию:

func startTimer() { 
    timer = NSTimer.scheduledTimerWithTimeInterval(updateInterval, target: self, selector: #selector(TableViewController.parseClanlordInformation), userInfo: nil, repeats: true) 
} 

И делегаты XML Parser настроены так:

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

Когда я запустить приложение таблица заполняется данные обычно, тогда, когда первое обновление запускает parser.parse() возвращает false в строке 80, столбце 1 или около него.

Почему это работает только один раз? Есть ли какой-то сброс, который я должен делать, что я забыл?

Спасибо за любую помощь.

+0

FYI - вам действительно нужно реорганизовать свой код, чтобы удаленный доступ к данным и синтаксический анализ XML выполнялись на фоновом потоке. – rmaddy

+0

Я согласен с повторным сетевым запросом и рекомендацией создать экземпляр нового 'NSXMLParser' для каждого анализа. В стороне, никогда не предполагайте, что содержимое определенного элемента будет возвращено в одном вызове 'foundCharacters'. Вся логика внутри 'foundCharacters' принадлежит' didEndElement'. 'didStartElement' должен инициализировать строковую переменную,' foundCharacters' должен просто присоединяться к этой строке, а 'didEndElement' должен выполнять всю логическую интерпретацию строки и действовать на нее. – Rob

+1

Благодарим вас за комментарии. Я рассмотрю вопрос о том, что это в фоновом потоке и поместим мою логику в didEndElement, как вы предлагаете. Очень информативно, я ценю! –

ответ

0

Я уверен, что данный экземпляр NSXMLParser может использоваться только один раз. Создавайте новый экземпляр каждый раз, когда вы хотите снова разобрать.

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

Это также означает, что вы можете удалить настройки парсера в viewDidLoad.