最近在学习RxSwift ,将学习的过程记录下来。
1、需要用到的相关库:
pod 'RxSwift'
pod 'RxCocoa'
pod 'RxDataSources'
pod 'Moya/RxSwift'
pod 'Moya'
pod 'HandyJSON'
2、使用的是Moya,实现TargetType 协议就可以了。
import Foundation
import Moya
let personalNetWorkProvider = MoyaProvider()
enum personalApi {
case personal(parameters:[String:Any],path_url:String)
}
extension personalApi: TargetType {
var baseURL: URL {
return URL.init(string: BaseURL)!
}
var path: String {
switch self {
case .personal(_,let path_url):
return path_url
}
}
var method: Moya.Method {
switch self {
case .personal(_,_):
return .post
}
}
var sampleData: Data {
return "".data(using: String.Encoding.utf8)!
}
var task: Task {
switch self {
case let .personal(parameters,_):
return .requestParameters(parameters: parameters, encoding: JSONEncoding.default)
}
}
var headers: [String : String]? {
return nil
}
}
3、将网络请求回的数据通过JSON转化成Mode ,需要进行一些准备。
import Foundation
import RxSwift
import Moya
import HandyJSON
extension ObservableType where E == Response {
public func mapHandyJsonModel(_ type: T.Type) -> Observable {
return flatMap { response -> Observable in
return Observable.just(response.mapHandyJsonModel(T.self))
}
}
}
extension Response {
func mapHandyJsonModel(_ type: T.Type) -> T {
let jsonString = String.init(data: data, encoding: .utf8)
if let modelT = JSONDeserializer.deserializeFrom(json: jsonString) {
return modelT
}
return JSONDeserializer.deserializeFrom(json: "{\"msg\":\"请求有误\"}")!
}
}
4、定义一个协议
import Foundation
protocol personalViewModeType {
//associatedtype: 关联类型为协议中的某个类型提供了一个占位名(或者说别名),其代表的实际类型在协议被采纳时才会被指定
associatedtype Input
associatedtype Output
func transform(input:Input)->Output//通过 transform 方法将input携带的数据进行处理,生成了一个Output
}
5、Model
import Foundation
import HandyJSON
import RxDataSources
struct personalModel: HandyJSON {
var data:tokenModel?
}
struct tokenModel: HandyJSON {
var token:String?
}
struct personalSection {
var items: [Item]
}
extension personalSection: SectionModelType {
typealias Item = personalModel // 重定义 Item 的类型为personalModel
//实现协议中的方式
init(original: personalSection,items: [personalSection.Item]) {
self = original
self.items = items
}
}
6、下面是ViewModel中全部代码
import UIKit
import RxSwift
import RxCocoa
import SwiftyJSON
import HandyJSON
import Reachability
import Moya
enum personalRefreshStatus { // tableView的刷新状态
case none
case beingHeaderRefresh
case endHeaderRefresh
case beingFooterRefresh
case endFooterRefresh
case noMoreData
}
class personalViewModel: NSObject {
let models = Variable<[personalModel]>([]) // 存放着解析完成的模型数组
private lazy var disposeBag = DisposeBag()
}
extension personalViewModel: personalViewModeType {
typealias Input = personInput
typealias Output = personaloutput
struct personInput {
}
struct personaloutput {
let sections:Driver<[personalSection]> // tableView的section数据
let requestCommond = PublishSubject<[String: Any]>() //传递参数进来进行网络请求
let refreshStatus = Variable(.none) // 告诉外界的tableView当前的刷新状态
init(sections:Driver<[personalSection]>) {
self.sections = sections
}
}
func transform(input: personalViewModel.personInput) -> personalViewModel.personaloutput {
let sections = models.asObservable().map { (models) -> [personalSection] in
return [personalSection(items:models)] // 当models的值被改变时会调用
}.asDriver(onErrorJustReturn: [])
let output = personaloutput(sections: sections)
output.requestCommond.subscribe(onNext: { [weak self] paratem in
//进行网络请求
guard (self?.isWifiNetwork())! else { return } // 判断网络状态
personalNetWorkProvider.rx.request(.personal(parameters: paratem, path_url: login_URL)).asObservable().mapHandyJsonModel(personalModel.self).subscribe({ [weak self] (event) in
metting_SVPDismiss() // 取消加载动画
output.refreshStatus.value = .endHeaderRefresh // 告诉外界刷新结束
switch event {
case let .next(classModel):
self?.models.value = [classModel]
break
case let .error(error):
warningTIps(waringStr: error as! String)
break
default:
break
}
}).disposed(by: (self?.disposeBag)!)
}).disposed(by: disposeBag)
return output
}
}
// MARK: - 网络数据
extension personalViewModel {
private func isWifiNetwork()-> Bool { // p判断当前连接的网络
let reachability = Reachability()! // 网络检测
switch reachability.connection {
case .wifi:
metting_SVPShow() // 显示加载动画
return true
case .none,.cellular:
alertDismiss(message: "当前不是Wi-Fi或者无网络连接,请连接Wi-Fi")
return false
}
}
}
7、最后是ViewController中代码
import UIKit
import RxCocoa
import RxSwift
import Then
import RxDataSources
import MJRefresh
class personalViewController: JFBaseViewController {
private lazy var disposeBag = DisposeBag()
let viewModel = personalViewModel()
private lazy var headView: personalHeaderView = {
let headView = personalHeaderView(frame: CGRect(x: 0, y: 0, width: kScreenW, height: AdaptH(90)))
return headView
}()
let tableView = UITableView().then {
$0.backgroundColor = kWhite
$0.register(personalTableViewCell.self, forCellReuseIdentifier: personalTableViewCell.identifier())
$0.tableFooterView = UIView()
}
let dataSource = RxTableViewSectionedReloadDataSource(configureCell: {(ds,tb,index,model) -> personalTableViewCell in
let cell = tb.dequeueReusableCell(withIdentifier: personalTableViewCell.identifier(), for: index) as? personalTableViewCell
cell?.textLabel?.text = model.data?.token
return cell!
},titleForHeaderInSection: {ds,index in
return String(index)
})
override func viewDidLoad() {
super.viewDidLoad()
setUpAll()
bindView()
}
}
extension personalViewController {
fileprivate func setUpAll() {
view.addSubview(tableView)
tableView.snp.makeConstraints { (make) in
make.edges.equalToSuperview()
}
}
}
// MARK: - 绑定数据
extension personalViewController {
fileprivate func bindView() {
tableView.rx.setDelegate(self).disposed(by: disposeBag)
let vmInput = personalViewModel.personInput() // 初始化input
let vmOutput = viewModel.transform(input: vmInput) // 通过transform得到output
vmOutput.sections.asDriver().drive(tableView.rx.items(dataSource: dataSource)).disposed(by: disposeBag)
vmOutput.refreshStatus.asObservable().subscribe(onNext: { [weak self] status in
//--
switch status {
case .beingHeaderRefresh:
self?.tableView.mj_header.beginRefreshing()
break
case .endHeaderRefresh:
self?.tableView.mj_header.endRefreshing()
break
case .beingFooterRefresh:
self?.tableView.mj_footer.beginRefreshing()
break
case .endFooterRefresh:
self?.tableView.mj_footer.endRefreshing()
break
case .noMoreData:
self?.tableView.mj_footer.endRefreshingWithNoMoreData()
break
default:
break
}
}).disposed(by: disposeBag)
tableView.tableHeaderView = headView
var parameter = [String: Any]()
parameter["userName"] = personal_userName
parameter["pass"] = personal_pass
vmOutput.requestCommond.onNext(parameter)
tableView.mj_header = MJRefreshNormalHeader(refreshingBlock: {
vmOutput.requestCommond.onNext(parameter)
})
tableView.rx.itemSelected.subscribe(onNext:{ [weak self] indexPath in
self?.tableView.deselectRow(at: indexPath, animated: true)
print(indexPath.row)
}).disposed(by: disposeBag)
}
}
// MARK: - UITableViewDelegate
extension personalViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return AdaptH(100)
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return AdaptH(50)
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView()
headerView.backgroundColor = kRed
return headerView
}
}
效果图:
参考地址:
https://www.jianshu.com/p/d8cf13724fe7
https://www.jianshu.com/p/406336b4aadc
https://www.jianshu.com/p/6678f28db333