Я читаю из 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 или около него.
Почему это работает только один раз? Есть ли какой-то сброс, который я должен делать, что я забыл?
Спасибо за любую помощь.
FYI - вам действительно нужно реорганизовать свой код, чтобы удаленный доступ к данным и синтаксический анализ XML выполнялись на фоновом потоке. – rmaddy
Я согласен с повторным сетевым запросом и рекомендацией создать экземпляр нового 'NSXMLParser' для каждого анализа. В стороне, никогда не предполагайте, что содержимое определенного элемента будет возвращено в одном вызове 'foundCharacters'. Вся логика внутри 'foundCharacters' принадлежит' didEndElement'. 'didStartElement' должен инициализировать строковую переменную,' foundCharacters' должен просто присоединяться к этой строке, а 'didEndElement' должен выполнять всю логическую интерпретацию строки и действовать на нее. – Rob
Благодарим вас за комментарии. Я рассмотрю вопрос о том, что это в фоновом потоке и поместим мою логику в didEndElement, как вы предлагаете. Очень информативно, я ценю! –