RxSwift + Moya + ObjectMapper

Posted youhui

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RxSwift + Moya + ObjectMapper相关的知识,希望对你有一定的参考价值。

https://www.jianshu.com/p/173915b943af

use_frameworks!
 
target 'RXDemo' do
    pod 'RxSwift'
    pod 'RxCocoa'
    pod 'Moya-ObjectMapper/RxSwift'
    pod 'Moya/RxSwift'
end
import Moya

let DouBanProvider = MoyaProvider<DouBanAPI>()

public enum DouBanAPI {
    case channels  //获取频道列表
    case playlist(String) //获取歌曲
}

extension DouBanAPI: TargetType {
 
    public var baseURL: URL {
        switch self {
        case .channels:
            return URL(string: "https://www.douban.com")!
        case .playlist(_):
            return URL(string: "https://douban.fm")!
        }
    }
    
    public var path: String {
        switch self {
        case .channels:
            return "/j/app/radio/channels"
        case .playlist(_):
            return "/j/mine/playlist"
        }
    }
    
    public var method: Moya.Method {
        return .get
    }

    public var task: Task {
        switch self {
        case .playlist(let channel):
            var params: [String: Any] = [:]
            params["channel"] = channel
            params["type"] = "n"
            params["from"] = "mainsite"
            return .requestParameters(parameters: params,
                                      encoding: URLEncoding.default)
        default:
            return .requestPlain
        }
    }
    
    public var validate: Bool {
        return false
    }
    
    public var sampleData: Data {
        return "{}".data(using: String.Encoding.utf8)!
    }
    
    public var headers: [String: String]? {
        return nil
    }
}
import UIKit
import ObjectMapper

//豆瓣接口模型
struct Douban: Mappable {
    //频道列表
    var channels: [Channel]?
    
    init?(map: Map) { }
    
    // Mappable
    mutating func mapping(map: Map) {
        channels <- map["channels"]
    }
}

//频道模型
struct Channel: Mappable {
    var name: String?
    var nameEn:String?
    var channelId: String?
    var seqId: Int?
    var abbrEn: String?
    
    init?(map: Map) { }
    
    // Mappable
    mutating func mapping(map: Map) {
        name <- map["name"]
        nameEn <- map["name_en"]
        channelId <- map["channel_id"]
        seqId <- map["seq_id"]
        abbrEn <- map["abbr_en"]
    }
}

//歌曲列表模型
struct Playlist: Mappable {
    var r: Int!
    var isShowQuickStart: Int!
    var song:[Song]!
    
    init?(map: Map) { }
    
    // Mappable
    mutating func mapping(map: Map) {
        r <- map["r"]
        isShowQuickStart <- map["is_show_quick_start"]
        song <- map["song"]
    }
}

//歌曲模型
struct Song: Mappable {
    var title: String!
    var artist: String!
    
    init?(map: Map) { }
    
    // Mappable
    mutating func mapping(map: Map) {
        title <- map["title"]
        artist <- map["artist"]
    }
}

  let data = DouBanProvider.rx.request(.channels)
            .mapObject(Douban.self)
            .map { $0.channels ?? [] }
            .asObservable()
        
        data.bind(to: self.tableView.rx.items) { tableView, _, channel in
            let cell = tableView.dequeueReusableCell(withIdentifier: "CellIdentifier")!
            cell.textLabel?.text = channel.name
            cell.accessoryType = .disclosureIndicator
            return cell
            }.disposed(by: self.disposeBag)
        
        tableView.rx.modelSelected(Channel.self)
            .map{ $0.channelId ?? "" }
            .flatMap { DouBanProvider.rx.request(.playlist($0)) }
            .mapObject(Playlist.self)
            .subscribe(onNext: { [weak self] (playList) in
                if playList.song != nil && playList.song.count > 0 {
                    let artist = playList.song[0].artist!
                    let title = playList.song[0].title!
                    let message = "歌手:(artist)
歌曲:(title)"
                    self?.showAlert(title: "歌曲信息", message: message)
                }
            }).disposed(by: self.disposeBag)
import RxSwift
import RxCocoa
import ObjectMapper

class DoubanService {

    //获取频道数据
    func loadChannels() -> Observable<[Channel]> {
        return DouBanProvider.rx.request(.channels)
            .mapObject(Douban.self)
            .map{ $0.channels ?? [] }
            .asObservable()
    }
    
    //获取歌曲列表数据
    func loadPlaylist(channelId: String) -> Observable<Playlist> {
        return DouBanProvider.rx.request(.playlist(channelId))
            .mapObject(Playlist.self)
            .asObservable()
    }
    
    //获取频道下第一首歌曲
    func loadFirstSong(channelId: String) -> Observable<Song> {
        return loadPlaylist(channelId: channelId)
            .filter{ $0.song != nil && $0.song.count > 0}
            .map{ $0.song[0] }
    }
}
import UIKit
import RxSwift
import RxCocoa

class MusicViewController: UIViewController {
    
    private var viewModel = MusicListViewModel()
    
    private var disposeBag = DisposeBag()
    
    private lazy var tableView: UITableView = {
        let tableView = UITableView(frame: self.view.bounds)
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "CellIdentifier")
        tableView.tableFooterView = UIView()
        return tableView
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.view.backgroundColor = .white
        
        self.view.addSubview(self.tableView)
        
        let service = DoubanService()
        
        //获取列表数据
        let data = service.loadChannels()
        
        //将数据绑定到表格
        data.bind(to: tableView.rx.items) { (tableView, row, element) in
            let cell = tableView.dequeueReusableCell(withIdentifier: "CellIdentifier")!
            cell.textLabel?.text = "(element.name!)"
            cell.accessoryType = .disclosureIndicator
            return cell
            }.disposed(by: disposeBag)
        
        //单元格点击
        tableView.rx.modelSelected(Channel.self)
            .map{ $0.channelId ?? "" }
            .flatMap(service.loadFirstSong)
            .subscribe(onNext: {[weak self] song in
                //将歌曲信息弹出显示
                let message = "歌手:(song.artist!)
歌曲:(song.title!)"
                self?.showAlert(title: "歌曲信息", message: message)
            }).disposed(by: disposeBag)
        
    }
    
    //显示消息
    func showAlert(title:String, message:String) {
        let alertController = UIAlertController(title: title,
                                                message: message, preferredStyle: .alert)
        let cancelAction = UIAlertAction(title: "确定", style: .cancel, handler: nil)
        alertController.addAction(cancelAction)
        self.present(alertController, animated: true, completion: nil)
    }
}

以上是关于RxSwift + Moya + ObjectMapper的主要内容,如果未能解决你的问题,请参考以下文章

RxSwift + Moya + ObjectMapper

使用 Moya + RxSwift 处理自定义错误响应

RxSwift/Moya - 如果通过函数返回序列将不会启动

如何使用 Moya RxSwift 合并 REST 数组

处理 UITableView 绑定中的连接错误(Moya、RxSwift、RxCocoa)

moya 与 RxSwift 使用