json数据解析(iOS)

JSON简介

JSON是一种轻量级的数据交换语言,以文字为基础,且易于让人阅读。尽管JSON是Javascript的一个子集,但JSON是独立于语言的文本格式,并且采用了类似于C语言家族的一些习惯。
iOS的SDK已经使开发人员可以轻松获取并解析JSON数据。它配备了一个方便的类称为NSJSONSerialization,它可以自动转换成JSON格式的数据对象。(iOS5发布)
这里提供一个豆瓣电影top250的API:https://api.douban.com/v2/movie/top250


创建类用于保存所需字段

用swift File创建新类movie命名为movie.swift

import Foundation
class Movie {
    var title:String = ""
    var genres:String = ""
    var averager:Double = 0.0
    var year:String = ""
}


NSURLSession网络通信http

我们定义豆瓣API为url,并声明movies变量(variable)作为存储movie对象的数组。

    let doubanMovieURL = "https://api.douban.com/v2/movie/top250"
    var movies = [Movie]()

接下来,插入以下方法:

    func parseJsonData(data:NSData) -> [Movie] {
        var movies = [Movie]() //Movie类的数组
        do{
            let jsonResult = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary
            
            let jsonMovies = jsonResult?["subjects"] as! [AnyObject]
            
            for jsonMovie in jsonMovies {
                let movie = Movie()
                    movie.title = jsonMovie["title"] as! String
                    movie.genres = jsonMovie["genres"] as! String
                    movie.year = jsonMovie["year"] as! String
                
                let rating = jsonMovie["rating"] as! [String:AnyObject]
                    movie.averager = rating["averager"] as! Double
                //class增加属性
                movies.append(movie)
                //数组增加
            }
        }
        catch{
            print(error)
            //JSONObjectWithData会throw error,try和catch捕获error
        }
        return movies
    }

我们首先创建NSURLSession的实例与豆瓣的API。该NSURLSession类是在iOS7时引入代替NSURLConnection的,它已经存在了好几年了。通过NSURLSession处理HTTP在线内容提供了更多的功能,更具有灵活性和力量。NSURLSession的改进功能是会话任务(task),其中处理数据的加载,以及上载和下载的文件和数据从服务器获取(例如JSON数据抓取 ​​)。通过session,可以安排三类任务:

  1. (NSURLSessionDataTask)用于检索数据存储,下载任务
  2. (NSURLSessionDownloadTask),用于将文件下载到硬盘,上传任务
  3. (NSURLSessionUploadTask)上传在磁盘上的文件。

在这里,我们使用的数据任务从豆瓣检索内容。为了把数据的任务添加到会话中,我们调用dataTaskWithURL方法用豆瓣指定URL。要启动数据任务,调用resume方法(即task.resume())。像网络API,NSURLSession API是异步的。一旦请求完成后,通过调用你的compeltion handler closure(完成处理闭包)关闭返回数据。


NSJSONSerialization解析json数据

NSJSONSerialization能将JSON数据转换为Foundation对象,也能将Foundation对象转换为JSON数据,转换为JSON的对象必须具有如下属性

  1. 顶层对象必须是NSArray或者NSDictionary
  2. 所有对象必须是NSString、NSNumber、NSArray、NSDictionary、NSNull的实例
  3. 所有NSDictionary的key必须是NSString类型
  4. 数字对象不能是非数值或无穷

在完成处理程序,返回的数据后,我们立刻检查错误,并调用parseJsonData方法。返回的data数据是JSON格式。我们创建了一个名为parseJsonData的方法,把JSON格式的数据转换成包含movie对象的数组。foundation框架提供了NSJSONSerialization类,它是能够转换JSON为Foundation对象和转换Foundation对象到JSON。在代码片段中,我们调用JSONObjectWithData方法给JSON数据进行转换。

当转换JSON格式数据为object(对象)时,顶级项通常转换为Dictionary(词典)或Array(数组)。在这种情况下,当前豆瓣API最高级目录的返回数据被转换为一个字典。您可以访问要使用的电影数据。你怎么知道用什么key?

你可以用下面的方法:

  1. 参考API文档
  2. 使用chrome浏览器插件FE助手看测试SON数据
  3. 也可以通过命令行curl http://api.douban.com/v2/movie/top250
    创建parseJsonData方法
    func parseJsonData(data:NSData) -> [Movie] {
        var movies = [Movie]() //Movie类的数组
        do{
            let jsonResult = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary

            let jsonMovies = jsonResult?["subjects"] as! [AnyObject]
//            for jsonMovie in jsonMovies{
//                let movie = Movie()
//                movie.title = jsonMovies["title"] as! String
//                //class增加属性
//                movies.append(movie)
//                //数组增加
            for jsonMovie in jsonMovies {
                let movie = Movie()
                movie.title = jsonMovie["title"] as! String
                //class属性赋值

                movies.append(movie) //数组增加
            }
        }
        catch{
            print(error)
            //JSONObjectWithData会throw error,try和catch捕获error
        }
        return movies
    }

我们可以使用subjects的key名来获得其中电影数组。

let jsonMovies = jsonResult?["subjects"] as! [AnyObject]

创建tableview展示

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        // Return the number of sections.
        return 1
    }
    
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // Return the number of rows in the section.
        return movies.count
    }
    
    
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! KivaLoanTableViewCell
        
        // Configure the cell...
        cell.titleLabel.text = movies[indexPath.row].title
        cell.genresLabel.text = movies[indexPath.row].genres
        cell.averagerLabel.text = "\(movies[indexPath.row].averager)"
        cell.yearLabel.text = movies[indexPath.row].year
        
        return cell
    }

当一个函数抛出一个错误时,你的程序流程会发生改变,所以重要的是你能迅速识别代码中会抛出错误的地方。为了标识出这些地方,在调用一个能抛出错误的函数、方法或者构造器之前,加上try关键字,或者try?或try!这种变体。这些关键字在下面的小节中有具体讲解。