2017-09-12 6 views
0

私はSwiftのXML解析を初めて行ったので、このコードをParsing XML from URL in Swiftに見つけましたが、コードを実行しようとするとEXC_BAD_INSTRUCTIONエラーが発生します。エラーの説明は、読み取りますfatal error: unexpectedly found nil while unwrapping an Optional valueSwiftのXML解析4

をこれは私の単純なXMLファイルです:

<xml> 
    <book> 
     <title>Book Title</title> 
     <author>Book Author</author> 
    </book> 
</xml> 

次のコードは、XMLParserオブジェクトを作成し、マイドキュメントにあるXMLファイルを解析します。ここで

// get xml file path from Documents and parse 

let filePath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last?.appendingPathComponent("example.xml") 

let parser = XMLParser(contentsOf: filePath!) 
parser?.delegate = self 

if (parser?.parse())! { 
    print(self.results) 
} 

私はXMLParserDelegateメソッドを実装し、私の辞書を定義します。currentDictionaryresults辞書に追加されたときに

// a few constants that identify what element names we're looking for inside the XML 

let recordKey = "book" 
let dictionaryKeys = ["title","author"] 

// a few variables to hold the results as we parse the XML 

var results: [[String: String]]!   // the whole array of dictionaries 
var currentDictionary: [String: String]! // the current dictionary 
var currentValue: String?     // the current value for one of the keys in the dictionary 

// start element 
// 
// - If we're starting a "record" create the dictionary that will hold the results 
// - If we're starting one of our dictionary keys, initialize `currentValue` (otherwise leave `nil`) 


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

    } 
} 

// found characters 
// 
// - If this is an element we care about, append those characters. 
// - If `currentValue` still `nil`, then do nothing. 

func parser(_ parser: XMLParser, foundCharacters string: String) { 

    currentValue? += string 

} 

// end element 
// 
// - If we're at the end of the whole dictionary, then save that dictionary in our array 
// - If we're at the end of an element that belongs in the dictionary, then save that value in the dictionary 


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 

    } 
} 

// Just in case, if there's an error, report it. (We don't want to fly blind here.) 

func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) { 

    print(parseError) 

    currentValue = nil 
    currentDictionary = nil 
    results = nil 

} 

エラーがdidEndElement方法に記載されています。

func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { 

    if elementName == recordKey { 

     results.append(currentDictionary) // Line with Error 
     currentDictionary = nil 

    } else if dictionaryKeys.contains(elementName) { 

     currentDictionary[elementName] = currentValue 
     currentValue = nil 

    } 
} 

この問題を解決するのを手伝ってください。私はParsing XML from URL in Swiftで提供されているまったく同じコードを使用しており、問題はないようです。私は間違って何かしていますか?

答えて

1

あなたのコードは実際にresultsを初期化することはありません。初めて使用しようとすると、nilの任意の値を強制的にアンラップしようとしています。それは良くないね。それを暗黙のうちにアンラップされたオプションとして宣言する理由はありません。あなたのparser(_:parseErrorOccurred:)方法から

results = nil 

:また、行を削除する必要があります

var results = [[String: String]]() 

var results: [[String: String]]! 

へ:

あなたが変更する必要があります。

あなたはむしろresultsは任意でなければならないなら、あなたはあなたのコードを次のように変更を加えることができます。

var results: [[String: String]]? = [[String: String]]() 

変更:

results.append(currentDictionary) 

resultsへの宣言

変更を〜へ:

results?.append(currentDictionary) 

results = nilの行はparser(_:parseErrorOccurred:)のままにしてください。

+0

を。私の最初の答えは、より大きな画像を見ることなく、クラッシュの原因にもっと焦点を合わせました。あなたのコメントは良いものです。私の答えは両方の可能なアプローチを反映しています。 – rmaddy

+0

私はそれが開始問題であることを知っていました。私はそれをオプションなしで試してみましたが、うまくいきませんでした。これは意味があります!君たちありがとう! @rob – user1526521

+0

@ user1526521 - あなたはrmaddyの答えを受け入れることをお勧めします。 「誰かが私の質問に答えたときに何をすべきですか?」(https://stackoverflow.com/help/someone-answers)を参照してください。 – Rob

0

rmaddyは問題を正しく診断しました(+1)。 resultsは決して初期化されませんでした。

私はほとんどそのままあなたのコードを残してお勧めしますが、単に次のようにresultsを初期化しparserDidStartDocument方法追加します。おかげで@Rob

func parserDidStartDocument(_ parser: XMLParser) { 
    results = [[:]] 
}