RxSwift之深入解析URLSession的数据请求和数据处理

一、请求网络数据

① 通过 rx.response 请求数据

  • 如下所示,通过豆瓣提供的音乐频道列表接口获取数据,并将返回结果输出到控制台中:
"https://www.douban.com/j/app/radio/channels" -i -v
Success (2134ms): Status 200
返回的数据是: {
    
    "channels":[{
    
    "name_en":"Personal Radio","seq_id":0,"abbr_en":"My","name":"私人兆赫","channel_id":0},{
    
    "name":"华语","seq_id":0,"abbr_en":"","channel_id":"1","name_en":""},{
    
    "name":"欧美","seq_id":1,"abbr_en":"","channel_id":"2","name_en":""},{
    
    "name":"七零","seq_id":2,"abbr_en":"","channel_id":"3","name_en":""},{
    
    "name":"八零","seq_id":3,"abbr_en":"","channel_id":"4","name_en":""},{
    
    "name":"九零","seq_id":4,"abbr_en":"","channel_id":"5","name_en":""},{
    
    "name":"粤语","seq_id":5,"abbr_en":"","channel_id":"6","name_en":""},{
    
    "name":"摇滚","seq_id":6,"abbr_en":"","channel_id":"7","name_en":""},{
    
    "name":"民谣","seq_id":7,"abbr_en":"","channel_id":"8","name_en":""},{
    
    "name":"轻音乐","seq_id":8,"abbr_en":"","channel_id":"9","name_en":""},{
    
    "name":"原声","seq_id":9,"abbr_en":"","channel_id":"10","name_en":""},{
    
    "name":"Fly by midnight ","seq_id":10,"abbr_en":"","channel_id":"267","name_en":""},{
    
    "name":"独立","seq_id":11,"abbr_en":"","channel_id":"268","name_en":""},{
    
    "name":"爵士","seq_id":12,"abbr_en":"","channel_id":"13","name_en":""},{
    
    "name":"电子","seq_id":13,"abbr_en":"","channel_id":"14","name_en":""},{
    
    "name":"说唱","seq_id":14,"abbr_en":"","channel_id":"15","name_en":""},{
    
    "name":"R&B ","seq_id":15,"abbr_en":"","channel_id":"16","name_en":""},{
    
    "name":"日语","seq_id":16,"abbr_en":"","channel_id":"17","name_en":""},{
    
    "name":"韩语","seq_id":17,"abbr_en":"","channel_id":"18","name_en":""},{
    
    "name":"我的巴比伦恋人","seq_id":18,"abbr_en":"","channel_id":"259","name_en":""},{
    
    "name":"女声","seq_id":19,"abbr_en":"","channel_id":"20","name_en":""},{
    
    "name":"法语","seq_id":20,"abbr_en":"","channel_id":"22","name_en":""},{
    
    "name":"户外","seq_id":21,"abbr_en":"","channel_id":"151","name_en":""},{
    
    "name":"休息","seq_id":22,"abbr_en":"","channel_id":"152","name_en":""},{
    
    "name":"工作学习","seq_id":23,"abbr_en":"","channel_id":"153","name_en":""},{
    
    "name":"亢奋","seq_id":24,"abbr_en":"","channel_id":"154","name_en":""},{
    
    "name":"古典","seq_id":25,"abbr_en":"","channel_id":"27","name_en":""},{
    
    "name":"动漫","seq_id":26,"abbr_en":"","channel_id":"28","name_en":""},{
    
    "name":"咖啡馆","seq_id":27,"abbr_en":"","channel_id":"32","name_en":""},{
    
    "name":"舒缓","seq_id":28,"abbr_en":"","channel_id":"155","name_en":""},{
    
    "name":"18岁青春的召唤","seq_id":29,"abbr_en":"","channel_id":"262","name_en":""},{
    
    "name":"红歌","seq_id":30,"abbr_en":"","channel_id":"41","name_en":""},{
    
    "name":"圣诞","seq_id":31,"abbr_en":"","channel_id":"170","name_en":""},{
    
    "name":"运动","seq_id":32,"abbr_en":"","channel_id":"257","name_en":""},{
    
    "name":"英语","seq_id":33,"abbr_en":"","channel_id":"264","name_en":""},{
    
    "name":"豆瓣好歌曲","seq_id":34,"abbr_en":"","channel_id":"179","name_en":""},{
    
    "name":"Future Pop","seq_id":35,"abbr_en":"","channel_id":"266","name_en":""},{
    
    "name":"金属","seq_id":36,"abbr_en":"","channel_id":"187","name_en":""},{
    
    "name":"布鲁斯","seq_id":37,"abbr_en":"","channel_id":"188","name_en":""},{
    
    "name":"新歌","seq_id":38,"abbr_en":"","channel_id":"61","name_en":""},{
    
    "name":"世界杯","seq_id":39,"abbr_en":"","channel_id":"201","name_en":""},{
    
    "name":"朋克","seq_id":40,"abbr_en":"","channel_id":"76","name_en":""},{
    
    "name":"Easy ","seq_id":41,"abbr_en":"","channel_id":"77","name_en":""},{
    
    "name":"91.1 ","seq_id":42,"abbr_en":"","channel_id":"78","name_en":""},{
    
    "name":"乡村","seq_id":43,"abbr_en":"","channel_id":"269","name_en":""},{
    
    "name":"“砖”属音乐","seq_id":44,"abbr_en":"","channel_id":"145","name_en":""},{
    
    "name":"Pop","seq_id":45,"abbr_en":"","channel_id":"194","name_en":""},{
    
    "name":"拉丁","seq_id":46,"abbr_en":"","channel_id":"189","name_en":""}]}
  • 请求示例如下:
// 创建URL对象
let urlString = "https://www.douban.com/j/app/radio/channels"
let url = URL(string:urlString)
// 创建请求对象
let request = URLRequest(url: url!)
 
// 创建并发起请求
URLSession.shared.rx.response(request: request).subscribe(onNext: {
    
    
    (response, data) in
    // 数据处理
    let str = String(data: data, encoding: String.Encoding.utf8)
    print("返回的数据是:", str ?? "")
}).disposed(by: disposeBag)
  • 从以上示例,可以看到,不管请求成功与否都会进入到 onNext 这个回调中,如果需要根据响应状态进行一些相应操作,比如:
    • 状态码在 200 ~ 300 则正常显示数据;
    • 如果是异常状态码(比如:404)则弹出告警提示框。
  • 可以借助 response 参数进行判断即可,把 url 改成一个错误的地址:
// 创建URL对象
let urlString = "https://www.douban.com/xxxxxxxxxx/app/radio/channels"
let url = URL(string:urlString)
// 创建请求对象
let request = URLRequest(url: url!)
 
// 创建并发起请求
URLSession.shared.rx.response(request: request).subscribe(onNext: {
    
    
    (response, data) in
    // 判断响应结果状态码
    if 200 ..< 300 ~= response.statusCode {
    
    
        let str = String(data: data, encoding: String.Encoding.utf8)
        print("请求成功!返回的数据是:", str ?? "")
    }else{
    
    
        print("请求失败!")
    }
}).disposed(by: disposeBag)
  • 运行结果如下:
curl -X GET 
"https://www.douban.com/xxxxxxxxxx/app/radio/channels" -i -v
Failure (1448ms): Status 404
请求失败!

② 通过 rx.data 请求数据

  • rx.data 与 rx.response 的区别:
    • 如果不需要获取底层的 response,只需知道请求是否成功,以及成功时返回的结果,那么建议使用 rx.data。
    • 因为 rx.data 会自动对响应状态码进行判断,只有成功的响应(状态码为 200~300)才会进入到 onNext 这个回调,否则进入 onError 这个回调。
  • 如果不需要考虑请求失败的情况,只对成功返回的结果做处理可以在 onNext 回调中进行相关操作:
// 创建URL对象
let urlString = "https://www.douban.com/j/app/radio/channels"
let url = URL(string:urlString)
// 创建请求对象
let request = URLRequest(url: url!)
 
// 创建并发起请求
URLSession.shared.rx.data(request: request).subscribe(onNext: {
    
    
    data in
    let str = String(data: data, encoding: String.Encoding.utf8)
    print("请求成功!返回的数据是:", str ?? "")
}).disposed(by: disposeBag)
  • 运行结果:
"https://www.douban.com/j/app/radio/channels" -i -v
Success (1449ms): Status 200
请求成功!返回的数据是: {
    
    "channels":[{
    
    "name_en":"Personal Radio","seq_id":0,"abbr_en":"My","name":"私人兆赫","channel_id":0},{
    
    "name":"华语","seq_id":0,"abbr_en":"","channel_id":"1","name_en":""},{
    
    "name":"欧美","seq_id":1,"abbr_en":"","channel_id":"2","name_en":""},{
    
    "name":"七零","seq_id":2,"abbr_en":"","channel_id":"3","name_en":""},{
    
    "name":"八零","seq_id":3,"abbr_en":"","channel_id":"4","name_en":""},{
    
    "name":"九零","seq_id":4,"abbr_en":"","channel_id":"5","name_en":""},{
    
    "name":"粤语","seq_id":5,"abbr_en":"","channel_id":"6","name_en":""},{
    
    "name":"摇滚","seq_id":6,"abbr_en":"","channel_id":"7","name_en":""},{
    
    "name":"民谣","seq_id":7,"abbr_en":"","channel_id":"8","name_en":""},{
    
    "name":"轻音乐","seq_id":8,"abbr_en":"","channel_id":"9","name_en":""},{
    
    "name":"原声","seq_id":9,"abbr_en":"","channel_id":"10","name_en":""},{
    
    "name":"Fly by midnight ","seq_id":10,"abbr_en":"","channel_id":"267","name_en":""},{
    
    "name":"独立","seq_id":11,"abbr_en":"","channel_id":"268","name_en":""},{
    
    "name":"爵士","seq_id":12,"abbr_en":"","channel_id":"13","name_en":""},{
    
    "name":"电子","seq_id":13,"abbr_en":"","channel_id":"14","name_en":""},{
    
    "name":"说唱","seq_id":14,"abbr_en":"","channel_id":"15","name_en":""},{
    
    "name":"R&B ","seq_id":15,"abbr_en":"","channel_id":"16","name_en":""},{
    
    "name":"日语","seq_id":16,"abbr_en":"","channel_id":"17","name_en":""},{
    
    "name":"韩语","seq_id":17,"abbr_en":"","channel_id":"18","name_en":""},{
    
    "name":"我的巴比伦恋人","seq_id":18,"abbr_en":"","channel_id":"259","name_en":""},{
    
    "name":"女声","seq_id":19,"abbr_en":"","channel_id":"20","name_en":""},{
    
    "name":"法语","seq_id":20,"abbr_en":"","channel_id":"22","name_en":""},{
    
    "name":"户外","seq_id":21,"abbr_en":"","channel_id":"151","name_en":""},{
    
    "name":"休息","seq_id":22,"abbr_en":"","channel_id":"152","name_en":""},{
    
    "name":"工作学习","seq_id":23,"abbr_en":"","channel_id":"153","name_en":""},{
    
    "name":"亢奋","seq_id":24,"abbr_en":"","channel_id":"154","name_en":""},{
    
    "name":"古典","seq_id":25,"abbr_en":"","channel_id":"27","name_en":""},{
    
    "name":"动漫","seq_id":26,"abbr_en":"","channel_id":"28","name_en":""},{
    
    "name":"咖啡馆","seq_id":27,"abbr_en":"","channel_id":"32","name_en":""},{
    
    "name":"舒缓","seq_id":28,"abbr_en":"","channel_id":"155","name_en":""},{
    
    "name":"18岁青春的召唤","seq_id":29,"abbr_en":"","channel_id":"262","name_en":""},{
    
    "name":"红歌","seq_id":30,"abbr_en":"","channel_id":"41","name_en":""},{
    
    "name":"圣诞","seq_id":31,"abbr_en":"","channel_id":"170","name_en":""},{
    
    "name":"运动","seq_id":32,"abbr_en":"","channel_id":"257","name_en":""},{
    
    "name":"英语","seq_id":33,"abbr_en":"","channel_id":"264","name_en":""},{
    
    "name":"豆瓣好歌曲","seq_id":34,"abbr_en":"","channel_id":"179","name_en":""},{
    
    "name":"Future Pop","seq_id":35,"abbr_en":"","channel_id":"266","name_en":""},{
    
    "name":"金属","seq_id":36,"abbr_en":"","channel_id":"187","name_en":""},{
    
    "name":"布鲁斯","seq_id":37,"abbr_en":"","channel_id":"188","name_en":""},{
    
    "name":"新歌","seq_id":38,"abbr_en":"","channel_id":"61","name_en":""},{
    
    "name":"世界杯","seq_id":39,"abbr_en":"","channel_id":"201","name_en":""},{
    
    "name":"朋克","seq_id":40,"abbr_en":"","channel_id":"76","name_en":""},{
    
    "name":"Easy ","seq_id":41,"abbr_en":"","channel_id":"77","name_en":""},{
    
    "name":"91.1 ","seq_id":42,"abbr_en":"","channel_id":"78","name_en":""},{
    
    "name":"乡村","seq_id":43,"abbr_en":"","channel_id":"269","name_en":""},{
    
    "name":"“砖”属音乐","seq_id":44,"abbr_en":"","channel_id":"145","name_en":""},{
    
    "name":"Pop","seq_id":45,"abbr_en":"","channel_id":"194","name_en":""},{
    
    "name":"拉丁","seq_id":46,"abbr_en":"","channel_id":"189","name_en":""}]}
  • 如果还要处理失败的情况,可以在 onError 回调中操作:
// 创建URL对象
let urlString = "https://www.douban.com/xxxxxx/app/radio/channels"
let url = URL(string:urlString)
// 创建请求对象
let request = URLRequest(url: url!)
 
// 创建并发起请求
URLSession.shared.rx.data(request: request).subscribe(onNext: {
    
    
    data in
    let str = String(data: data, encoding: String.Encoding.utf8)
    print("请求成功!返回的数据是:", str ?? "")
}, onError: {
    
     error in
    print("请求失败!错误原因:", error)
}).disposed(by: disposeBag)
  • 运行结果:
"https://www.douban.com/xxxxxx/app/radio/channels" -i -v
Failure (7189ms): Status 404
请求失败!错误原因: HTTP request failed with `404`.

二、手动发起请求和取消请求

  • 在很多情况下,网络请求并不是由程序自动发起的,可能需要我们点击个按钮,或者切换个标签时才去请求数据。除了手动发起请求外,同样的可能还需要手动取消上一次的网络请求(如果未完成),那么 RxSwift 该如何实现呢?
  • 如下所示:
    • 每次点击“发起请求”按钮则去请求一次数据;
    • 如果请求没返回时,点击“取消请求”则可将其取消(取消后即使返回数据也不作处理)。
//“发起请求”按钮
    @IBOutlet weak var startBtn: UIButton!
     
    //“取消请求”按钮
    @IBOutlet weak var cancelBtn: UIButton!
     
    let disposeBag = DisposeBag()
     
    override func viewDidLoad() {
    
    
        super.viewDidLoad()
         
        //创建URL对象
        let urlString = "https://www.douban.com/j/app/radio/channels"
        let url = URL(string:urlString)
        //创建请求对象
        let request = URLRequest(url: url!)
         
        //发起请求按钮点击
        startBtn.rx.tap.asObservable()
            .flatMap {
    
    
                URLSession.shared.rx.data(request: request)
                    .takeUntil(self.cancelBtn.rx.tap) //如果“取消按钮”点击则停止请求
            }
            .subscribe(onNext: {
    
    
                data in
                let str = String(data: data, encoding: String.Encoding.utf8)
                print("请求成功!返回的数据是:", str ?? "")
            }, onError: {
    
     error in
                print("请求失败!错误原因:", error)
            }).disposed(by: disposeBag)

三、将结果转为 Json 对象

  • 如果服务器返回的数据是 json 格式的话,可以使用 iOS 内置的 JSONSerialization 将其转成 JSON 对象,方便使用:
// 创建URL对象
let urlString = "https://www.douban.com/j/app/radio/channels"
let url = URL(string:urlString)
// 创建请求对象
let request = URLRequest(url: url!)
 
// 创建并发起请求
URLSession.shared.rx.data(request: request).subscribe(onNext: {
    
    
    data in
    let json = try? (JSONSerialization.jsonObject(with: data, options: .allowFragments)
                     as! [String: Any])
    print("--- 请求成功,返回的如下数据 ---")
    print(json!)
}).disposed(by: disposeBag)
  • 运行结果如下:
"https://www.douban.com/j/app/radio/channels" -i -v
Success (3410ms): Status 200
--- 请求成功!返回的如下数据 ---
["channels": <__NSArrayI 0x7ff0f2f07080>(
{
    
    
    "abbr_en" = "";
    "channel_id" = 9;
    name = "\U8f7b\U97f3\U4e50";
    "name_en" = "";
    "seq_id" = 8;
},
{
    
    
    "abbr_en" = "";
    "channel_id" = 10;
    name = "\U539f\U58f0";
    "name_en" = "";
    "seq_id" = 9;
},
{
    
    
    "abbr_en" = "";
    "channel_id" = 267;
    name = "Fly by midnight ";
    "name_en" = "";
    "seq_id" = 10;
},
{
    
    
    "abbr_en" = "";
    "channel_id" = 268;
    name = "\U72ec\U7acb";
    "name_en" = "";
    "seq_id" = 11;
},
{
    
    
    "abbr_en" = "";
    "channel_id" = 13;
    name = "\U7235\U58eb";
    "name_en" = "";
    "seq_id" = 12;
},
{
    
    
    "abbr_en" = "";
    "channel_id" = 14;
    name = "\U7535\U5b50";
    "name_en" = "";
    "seq_id" = 13;
},
{
    
    
    "abbr_en" = "";
    "channel_id" = 15;
    name = "\U8bf4\U5531";
    "name_en" = "";
    "seq_id" = 14;
},
{
    
    
    "abbr_en" = "";
    "channel_id" = 16;
    name = "R&B ";
    "name_en" = "";
    "seq_id" = 15;
},
{
    
    
    "abbr_en" = "";
    "channel_id" = 17;
    name = "\U65e5\U8bed";
    "name_en" = "";
    "seq_id" = 16;
},
{
    
    
    "abbr_en" = "";
    "channel_id" = 18;
    name = "\U97e9\U8bed";
    "name_en" = "";
    "seq_id" = 17;
},
{
    
    
    "abbr_en" = "";
    "channel_id" = 259;
    name = "\U6211\U7684\U5df4\U6bd4\U4f26\U604b\U4eba";
    "name_en" = "";
    "seq_id" = 18;
},
{
    
    
    "abbr_en" = "";
    "channel_id" = 20;
    name = "\U5973\U58f0";
    "name_en" = "";
    "seq_id" = 19;
},
{
    
    
    "abbr_en" = "";
    "channel_id" = 22;
    name = "\U6cd5\U8bed";
    "name_en" = "";
    "seq_id" = 20;
},
{
    
    
    "abbr_en" = "";
    "channel_id" = 151;
    name = "\U6237\U5916";
    "name_en" = "";
    "seq_id" = 21;
},
{
    
    
    "abbr_en" = "";
    "channel_id" = 152;
    name = "\U4f11\U606f";
    "name_en" = "";
    "seq_id" = 22;
},
{
    
    
    "abbr_en" = "";
    "channel_id" = 28;
    name = "\U52a8\U6f2b";
    "name_en" = "";
    "seq_id" = 26;
},
{
    
    
    "abbr_en" = "";
    "channel_id" = 32;
    name = "\U5496\U5561\U9986";
    "name_en" = "";
    "seq_id" = 27;
},
{
    
    
    "abbr_en" = "";
    "channel_id" = 155;
    name = "\U8212\U7f13";
    "name_en" = "";
    "seq_id" = 28;
},
{
    
    
    "abbr_en" = "";
    "channel_id" = 262;
    name = "18\U5c81\U9752\U6625\U7684\U53ec\U5524";
    "name_en" = "";
    "seq_id" = 29;
},
{
    
    
    "abbr_en" = "";
    "channel_id" = 41;
    name = "\U7ea2\U6b4c";
    "name_en" = "";
    "seq_id" = 30;
},
{
    
    
    "abbr_en" = "";
    "channel_id" = 170;
    name = "\U5723\U8bde";
    "name_en" = "";
    "seq_id" = 31;
},
{
    
    
    "abbr_en" = "";
    "channel_id" = 257;
    name = "\U8fd0\U52a8";
    "name_en" = "";
    "seq_id" = 32;
},
{
    
    
    "abbr_en" = "";
    "channel_id" = 264;
    name = "\U82f1\U8bed";
    "name_en" = "";
    "seq_id" = 33;
},
{
    
    
    "abbr_en" = "";
    "channel_id" = 179;
    name = "\U8c46\U74e3\U597d\U6b4c\U66f2";
    "name_en" = "";
    "seq_id" = 34;
}
)
]
  • 也可以在订阅前就进行转换:
// 创建URL对象
let urlString = "https://www.douban.com/j/app/radio/channels"
let url = URL(string:urlString)
// 创建请求对象
let request = URLRequest(url: url!)
 
// 创建并发起请求
URLSession.shared.rx.data(request: request)
    .map {
    
    
        try JSONSerialization.jsonObject(with: $0, options: .allowFragments)
            as! [String: Any]
    }
    .subscribe(onNext: {
    
    
        data in
        print("--- 请求成功!返回的如下数据 ---")
        print(data)
    }).disposed(by: disposeBag)
  • 还有更简单的方法,就是直接使用 RxSwift 提供的 rx.json 方法去获取数据,它会直接将结果转成 Json 对象:
// 创建URL对象
let urlString = "https://www.douban.com/j/app/radio/channels"
let url = URL(string:urlString)
// 创建请求对象
let request = URLRequest(url: url!)
 
// 创建并发起请求
URLSession.shared.rx.json(request: request).subscribe(onNext: {
    
    
    data in
    let json = data as! [String: Any]
    print("--- 请求成功!返回的如下数据 ---")
    print(json )
}).disposed(by: disposeBag)
  • 将获取到的豆瓣频道列表数据转换成 Json 对象,并绑定到表格上显示:
// 创建表格视图
self.tableView = UITableView(frame: self.view.frame, style:.plain)
// 创建一个重用的单元格
self.tableView!.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
self.view.addSubview(self.tableView!)
 
// 创建URL对象
let urlString = "https://www.douban.com/j/app/radio/channels"
let url = URL(string:urlString)
// 创建请求对象
let request = URLRequest(url: url!)
 
// 获取列表数据
let data = URLSession.shared.rx.json(request: request)
    .map{
    
     result -> [[String: Any]] in
        if let data = result as? [String: Any],
            let channels = data["channels"] as? [[String: Any]] {
    
    
                return channels
        }else{
    
    
                return []
        }
}
 
// 将数据绑定到表格
data.bind(to: tableView.rx.items) {
    
     (tableView, row, element) in
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")!
    cell.textLabel?.text = "\(row)\(element["name"]!)"
    return cell
}.disposed(by: disposeBag)
  • 效果如下:

在这里插入图片描述

四、将结果映射成自定义对象

① 准备工作

  • 要实现数据到模型(model)的转换,首先需要引入一个第三方的数据模型转换框架:ObjectMapper。
  • 为了让 ObjectMapper 能够更好地与 RxSwift 配合使用,对 Observable 进行扩展(RxObjectMapper.swift),增加数据转模型对象、以及数据转模型对象数组这两个方法:
import ObjectMapper
import RxSwift
 
// 数据映射错误
public enum RxObjectMapperError: Error {
    
    
    case parsingError
}
 
// 扩展Observable:增加模型映射方法
public extension Observable where Element:Any {
    
    
    // 将Json数据转成对象
    public func mapObject< T>(type:T.Type) -> Observable<T> where T:Mappable {
    
    
        let mapper = Mapper<T>()
        return self.map {
    
     (element) -> T in
            guard let parsedElement = mapper.map(JSONObject: element) else {
    
    
                throw RxObjectMapperError.parsingError
            }
            return parsedElement
        }
    }
     
    // 将Json数据转成数组
    public func mapArray< T>(type:T.Type) -> Observable<[T]> where T:Mappable {
    
    
        let mapper = Mapper<T>()
        return self.map {
    
     (element) -> [T] in
            guard let parsedArray = mapper.mapArray(JSONObject: element) else {
    
    
                throw RxObjectMapperError.parsingError
            }
            return parsedArray
        }
    }
}

② 使用示例

  • 以豆瓣音乐频道数据为例,首先定义好相关模型(需要实现 ObjectMapper 的 Mappable 协议,并设置好成员对象与 Json 属性的相互映射关系):
// 豆瓣接口模型
class Douban: Mappable {
    
    
    // 频道列表
    var channels: [Channel]?
     
    init(){
    
    
    }
     
    required init?(map: Map) {
    
    
    }
     
    // Mappable
    func mapping(map: Map) {
    
    
        channels <- map["channels"]
    }
}
 
// 频道模型
class Channel: Mappable {
    
    
    var name: String?
    var nameEn:String?
    var channelId: String?
    var seqId: Int?
    var abbrEn: String?
     
    init(){
    
    
    }
     
    required init?(map: Map) {
    
    
    }
     
    // Mappable
    func mapping(map: Map) {
    
    
        name <- map["name"]
        nameEn <- map["name_en"]
        channelId <- map["channel_id"]
        seqId <- map["seq_id"]
        abbrEn <- map["abbr_en"]
    }
}
  • 如下所示,获取数据,并转换成对应的模型:
// 创建URL对象
let urlString = "https://www.douban.com/j/app/radio/channels"
let url = URL(string:urlString)
// 创建请求对象
let request = URLRequest(url: url!)
 
// 创建并发起请求
URLSession.shared.rx.json(request: request)
    .mapObject(type: Douban.self)
    .subscribe(onNext: {
    
     (douban: Douban) in
        if let channels = douban.channels {
    
    
            print("--- 共\(channels.count)个频道 ---")
            for channel in channels {
    
    
                if let name = channel.name, let channelId = channel.channelId {
    
    
                    print("\(name) (id:\(channelId))")
                }
            }
        }
    }).disposed(by: disposeBag)
  • 如下所示,将数据换成模型,并绑定到表格上显示:
// 创建表格视图
self.tableView = UITableView(frame: self.view.frame, style:.plain)
// 创建一个重用的单元格
self.tableView!.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
self.view.addSubview(self.tableView!)

// 创建URL对象
let urlString = "https://www.douban.com/j/app/radio/channels"
let url = URL(string:urlString)
// 创建请求对象
let request = URLRequest(url: url!)

// 获取列表数据
let data = URLSession.shared.rx.json(request: request)
   .mapObject(type: Douban.self)
   .map{
    
     $0.channels ?? []}

// 将数据绑定到表格
data.bind(to: tableView.rx.items) {
    
     (tableView, row, element) in
   let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")!
   cell.textLabel?.text = "\(row)\(element.name!)"
   return cell
}.disposed(by: disposeBag)

猜你喜欢

转载自blog.csdn.net/Forever_wj/article/details/121308084