iOS Swift JSON解析教程
在本教程中,我们将学习如何使用Swift在我们的iOS应用程序中解析JSON响应。
我们将在UITableView中显示已解析的响应。
要了解有关UITableView的更多信息,请先阅读本教程,然后再继续。
Swift JSON解析
JSON是最常用的从Web服务发送和接收数据的格式。
数据采用键值对的形式。
使用Swift字典,我们可以轻松地从键中获取值。
在本教程中,我们将解析本地资源文件中的JSON数据。
JSONSerialization类用于通过转换Data对象将JSON数据解析为键值对字典。
JSON数据的类型为[String:Any]
。
让我们创建一个单视图iOS应用程序,其中将本地创建的JSON文件中的数据解析到TableView中。
iOS JSON解析示例项目结构
在Main.storyboard中,我们向ViewController添加了标签和TableView。
我们已经将TableView委托设置为ViewController。
有关如何使用Storyboard设置TableView的更多信息,请参考本教程。
Swift JSON解析代码
我们将从文件中解析JSON数据。response.json
文件如下所示:
序列化数据
let url = Bundle.main.url(forResource: "response", withExtension: "json") guard let jsonData = url else{return} guard let data = try? Data(contentsOf: jsonData) else { return } guard let json = try? JSONSerialization.jsonObject(with: data, options: []) else{return}
在上面的代码中,我们通过Bundle.main.url
实例获取文件。
Data实例将其转换为Data格式,然后将其序列化为JSON。
从JSON实例获取数据
现在我们有了JSON实例,我们可以通过以下方式获取数据:
if let dictionary = json as? [String: Any] { if let title = dictionary["title"] as? String { labelHeader.text = title } if let year = dictionary["year"] as? Double { print("Year is \(year)") } if let more_info = dictionary["more_info"] as? Double { //This doesn't get printed. print("More_info is \(more_info)") } for (key, value) in dictionary { print("Key is: \(key) and value is \(value)" ) } }
在TableView中,我们将填充另一个JSON文件:
ViewController.swift
import UIKit class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { @IBOutlet weak var labelHeader: UILabel! @IBOutlet weak var tableView: UITableView! var movieList = [MarvelData]() override func viewDidLoad() { super.viewDidLoad() //Do any additional setup after loading the view, typically from a nib. let url = Bundle.main.url(forResource: "response", withExtension: "json") guard let jsonData = url else{ print("data not found") return } guard let data = try? Data(contentsOf: jsonData) else { return } guard let json = try? JSONSerialization.jsonObject(with: data, options: []) else{return} if let dictionary = json as? [String: Any] { if let title = dictionary["title"] as? String { labelHeader.text = title } if let year = dictionary["year"] as? Double { print("Year is \(year)") } if let more_info = dictionary["more_info"] as? Double { //This doesn't get printed. print("More_info is \(more_info)") } for (key, value) in dictionary { print("Key is: \(key) and value is \(value)" ) } } //Now lets populate our TableView let newUrl = Bundle.main.url(forResource: "marvel", withExtension: "json") guard let j = newUrl else{ print("data not found") return } guard let d = try? Data(contentsOf: j) else { print("failed") return } guard let rootJSON = try? JSONSerialization.jsonObject(with: d, options: []) else{ print("failedh") return } if let JSON = rootJSON as? [String: Any] { labelHeader.text = JSON["title"] as? String guard let jsonArray = JSON["movies"] as? [[String: Any]] else { return } print(jsonArray) let name = jsonArray[0]["name"] as? String print(name ?? "NA") print(jsonArray.last!["year"] as? Int ?? 1970) for json in jsonArray { guard let movieName = json["name"] as? String else{ return } guard let movieYear = json["year"] as? Int else{ return } movieList.append(MarvelData(movieName: movieName, movieYear: movieYear)) } self.tableView.reloadData() } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() //Dispose of any resources that can be recreated. } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return movieList.count } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let currentMovie = movieList[indexPath.row] let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as UITableViewCell cell.textLabel?.text = currentMovie.movieName cell.detailTextLabel?.text = "\(currentMovie.movieYear)" return cell } } struct MarvelData { let movieName: String let movieYear: Int public init(movieName: String, movieYear: Int) { self.movieName = movieName self.movieYear = movieYear } }
在上面的代码中,我们还解析了第二个json文件,并将每个JSON Array元素追加到保存结构的数组中。
为了显示这些数据,我们必须在tableView实例上调用reloadData()
。
我们可以使在结构实例中设置json值的代码更好。
struct MarvelData { var movieName: String var movieYear: Int init(_ dictionary: [String: Any]) { self.movieName = dictionary["name"] as? String ?? "NA" self.movieYear = dictionary["year"] as? Int ?? 1970 } }
这样做我们可以更改:
guard let movieName = json["name"] as? String else{ return } guard let movieYear = json["year"] as? Int else{ return } movieList.append(MarvelData(movieName: movieName, movieYear: movieYear))
至
movieList.append(MarvelData(json))
无需使用for循环遍历jsonArray,我们可以轻松地在Swift中使用方便的运算符concatMap。
所以这:
for json in jsonArray { movieList.append(MarvelData(json)) }
更改为
movieList = jsonArray.compactMap{return MarvelData(##代码##)} //or movieList = jsonArray.compactMap{MarvelData(##代码##)} //or movieList = jsonArray.compactMap(MarvelData.init)