RxSwift + Moya + ObjectMapper

时间:2022-09-07 20:58:12

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)\n歌曲:\(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!)\n歌曲:\(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)
}
}