在iOS开发中,只要是涉及到网络的应用,几乎都离不开JSON或者XML。但是目前比较常见的是JSON数据格式。
JSON解析
JSON解析的第三方库有很多,我们这里只讲一种第三方库JSONKit和官方的解析方法。
JSONKit
首先把JSON格式的数据转换成String
,然后再调用JSONKit
定义的jsonStr.objectFromJSONString
方法,就可以转换成一个字典,方便我们使用。(JSONKit
请自己下载)
@IBAction func extractJSONWithJSONKit() {
if let url = URL(string: urlStr) {
if let jsonStr = try? String(contentsOf: url) as NSString {
let dict = jsonStr.objectFromJSONString() as! Dictionary<String, Any>
print(dict)
show(text: "解析成功")
}
}
else {
show(text: "解析失败")
}
}
JSONSerialization
其实官方的解析方法也非常简单,调用URLSession
的dataTask(with: completionHandler:)
方法,然后在completionHandler
回调里面就能得到我们想要的数据。如果error
不为空或者data
为nil
,意味着解析错误或者服务器没有数据,那么用return
返回。回调里面实在子线程中执行的,所以要回到主线程中更新UI。
@IBAction func extractJSONWithJSONSerialization() {
if let url = URL(string: urlStr) {
let reqeust = URLRequest(url: url)
let task = URLSession.shared.dataTask(with: reqeust, completionHandler: { (data, response, error) in
if error != nil || data == nil {
DispatchQueue.main.sync { // 在主线程中更新UI
self.show(text: "请求失败")
}
return
}
if let dict = try? JSONSerialization.jsonObject(with: data!, options: .mutableLeaves) as? Dictionary<String, Any> {
print(dict! as Any)
DispatchQueue.main.sync { // 在主线程中更新UI
self.show(text: "解析成功")
}
}
})
task.resume()
}
}
XML解析
XML的解析方式有两种:1)DOM:一次性将整个文档加载进内存,比较适合解析小文件,其中一个常用的第三方框架是GDataXML
;2)SAX:从根元素开始,按顺序一个个元素往下解析,比较适合大文件,苹果自带的XMLParser
就属于这个类型。
XMLParser
XMLParser
是通过代理的方式实现的,它一边解析,一边通知代理。
@IBAction func extractXMLWithXMLParser() {
let path = Bundle.main.path(forResource: "info.xml", ofType: nil)!
if let data = try? NSData.init(contentsOfFile: path) as Data {
parser = XMLParser(data: data)
parser.delegate = self
parser.parse() // 开始解析
}
}
// MARK: - XMLParserDelegate
extension ViewController: XMLParserDelegate {
// 解析到文档开头调用
func parserDidStartDocument(_ parser: XMLParser) {
print("parserDidStartDocument")
}
// 解析到一个元素的开始就会调用
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
print("-------didStartElement-------")
print(elementName)
print(namespaceURI as Any)
print(attributeDict)
print("-------didStartElement-------")
}
// 解析到节点时调用
func parser(_ parser: XMLParser, foundCharacters string: String) {
print("-------foundCharacters-------")
print(string)
print("-------foundCharacters-------")
}
// 解析到一个元素的结尾就会调用
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
print("-------didEndElement-------")
print(elementName)
print(namespaceURI as Any)
print(qName as Any)
print("-------didEndElement-------")
}
// 解析到文档结尾调用
func parserDidEndDocument(_ parser: XMLParser) {
print("parserDidEndDocument")
}
}
GDataXML
我们把GDataXML
的.m
和.h
拖到项目中后,需要做一下配置:
- 在
Target -> Build Phases -> Link Binary With Libraries
添加libxml2.2.tbd
- 在
Build Settings -> Header Search Paths
添加/usr/include/libxml2
- 在
Build Settings -> Other Linker Flags
添加-lxml2
- 如果
GDataXML
是MRC版本,不支持ARC,需要在Build Phases -> Compile Sources
找到GDataXMLNode.m
,在后面的Compiler Flags
加上-fno-objc-arc
解析过程如下:
@IBAction func extractXMLWithGDataXML() {
let path = Bundle.main.path(forResource: "info.xml", ofType: nil)!
if let data = try? NSData(contentsOfFile: path) as Data {
// 加载整个XML
if let doc = try? GDataXMLDocument(data: data, options: 0) {
// 获取根节点
let rootDoc = doc.rootElement()!
// 获取所有city节点
if let cities = rootDoc.elements(forName: "city") as? [GDataXMLElement] {
for city in cities {
// 获取name节点
let name = city.elements(forName: "name").first as! GDataXMLElement
print(name.stringValue())
}
}
}
}
}
Demo地址 >>
如果文中有错误,请指出!我们共同学习,共同进步。谢谢!