Skip to content

Commit 4a2a1cc

Browse files
author
田全军
committed
Moya+ObjectMapper+MJRefresh构建网络请求和刷新
1 parent 3253080 commit 4a2a1cc

File tree

11 files changed

+400
-87
lines changed

11 files changed

+400
-87
lines changed

RxSwift-Table-Collection1/.DS_Store

0 Bytes
Binary file not shown.

RxSwift-Table-Collection1/RxSwift-Table-Collection.xcodeproj/project.pbxproj

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
4705E0BC1F6CBF970063F566 /* InputValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4705E0BB1F6CBF970063F566 /* InputValidator.swift */; };
2222
4705E0BE1F6CC1430063F566 /* ResultProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4705E0BD1F6CC1430063F566 /* ResultProtocol.swift */; };
2323
4705E0C21F6CD6EB0063F566 /* RegisterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4705E0C11F6CD6EB0063F566 /* RegisterViewModel.swift */; };
24+
4726CBB91F7E675B0050E6BE /* ObservableObjectMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4726CBB81F7E675B0050E6BE /* ObservableObjectMapper.swift */; };
25+
4726CBBB1F7E6B330050E6BE /* ReponseObjectMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4726CBBA1F7E6B330050E6BE /* ReponseObjectMapper.swift */; };
26+
4726CBBD1F7F337E0050E6BE /* BaseViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4726CBBC1F7F337E0050E6BE /* BaseViewModel.swift */; };
2427
474136161F6FE0240069902B /* RxTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 474136141F6FE0240069902B /* RxTableViewController.swift */; };
2528
474136171F6FE0240069902B /* RxTableViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 474136151F6FE0240069902B /* RxTableViewController.xib */; };
2629
4741361B1F6FFA120069902B /* AnchorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4741361A1F6FFA120069902B /* AnchorViewModel.swift */; };
@@ -52,6 +55,9 @@
5255
4705E0BB1F6CBF970063F566 /* InputValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputValidator.swift; sourceTree = "<group>"; };
5356
4705E0BD1F6CC1430063F566 /* ResultProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResultProtocol.swift; sourceTree = "<group>"; };
5457
4705E0C11F6CD6EB0063F566 /* RegisterViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RegisterViewModel.swift; sourceTree = "<group>"; };
58+
4726CBB81F7E675B0050E6BE /* ObservableObjectMapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObservableObjectMapper.swift; sourceTree = "<group>"; };
59+
4726CBBA1F7E6B330050E6BE /* ReponseObjectMapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReponseObjectMapper.swift; sourceTree = "<group>"; };
60+
4726CBBC1F7F337E0050E6BE /* BaseViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseViewModel.swift; sourceTree = "<group>"; };
5561
474136141F6FE0240069902B /* RxTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxTableViewController.swift; sourceTree = "<group>"; };
5662
474136151F6FE0240069902B /* RxTableViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RxTableViewController.xib; sourceTree = "<group>"; };
5763
4741361A1F6FFA120069902B /* AnchorViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnchorViewModel.swift; sourceTree = "<group>"; };
@@ -162,6 +168,7 @@
162168
children = (
163169
4741361A1F6FFA120069902B /* AnchorViewModel.swift */,
164170
4741361C1F70A86E0069902B /* NetworkTools.swift */,
171+
4726CBBC1F7F337E0050E6BE /* BaseViewModel.swift */,
165172
);
166173
path = ViewModels;
167174
sourceTree = "<group>";
@@ -221,6 +228,15 @@
221228
path = Views;
222229
sourceTree = "<group>";
223230
};
231+
4726CBB51F7E64E90050E6BE /* Tools */ = {
232+
isa = PBXGroup;
233+
children = (
234+
4726CBB81F7E675B0050E6BE /* ObservableObjectMapper.swift */,
235+
4726CBBA1F7E6B330050E6BE /* ReponseObjectMapper.swift */,
236+
);
237+
path = Tools;
238+
sourceTree = "<group>";
239+
};
224240
474136221F70A8F40069902B /* Model */ = {
225241
isa = PBXGroup;
226242
children = (
@@ -250,6 +266,7 @@
250266
6A0DF5B11F6C0CFC002827B3 /* RxSwift-Table-Collection */ = {
251267
isa = PBXGroup;
252268
children = (
269+
4726CBB51F7E64E90050E6BE /* Tools */,
253270
4705E0941F6CB8660063F566 /* 登录注册 */,
254271
4705E0991F6CB8660063F566 /* UICollectionView */,
255272
4705E09E1F6CB8660063F566 /* UITableView */,
@@ -432,16 +449,19 @@
432449
files = (
433450
4741361D1F70A86E0069902B /* NetworkTools.swift in Sources */,
434451
474136241F70A8FF0069902B /* AnchorModel.swift in Sources */,
452+
4726CBB91F7E675B0050E6BE /* ObservableObjectMapper.swift in Sources */,
435453
4705E0B91F6CB9820063F566 /* RegisterViewController.swift in Sources */,
436454
4705E0A71F6CB8AA0063F566 /* RxCollectionViewController.swift in Sources */,
437455
4705E0B11F6CB8D60063F566 /* RxTableViewCell.swift in Sources */,
438456
474136161F6FE0240069902B /* RxTableViewController.swift in Sources */,
439457
474136271F70A9B70069902B /* RxCollectionViewCell.swift in Sources */,
440458
6A0DF5B51F6C0CFC002827B3 /* ViewController.swift in Sources */,
441459
4705E0BC1F6CBF970063F566 /* InputValidator.swift in Sources */,
460+
4726CBBB1F7E6B330050E6BE /* ReponseObjectMapper.swift in Sources */,
442461
4741361B1F6FFA120069902B /* AnchorViewModel.swift in Sources */,
443462
4705E0B51F6CB9530063F566 /* LoginViewController.swift in Sources */,
444463
6A0DF5B31F6C0CFC002827B3 /* AppDelegate.swift in Sources */,
464+
4726CBBD1F7F337E0050E6BE /* BaseViewModel.swift in Sources */,
445465
4705E0C21F6CD6EB0063F566 /* RegisterViewModel.swift in Sources */,
446466
4705E0BE1F6CC1430063F566 /* ResultProtocol.swift in Sources */,
447467
4705E0AE1F6CB8C90063F566 /* HeroViewModel.swift in Sources */,
@@ -519,6 +539,7 @@
519539
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
520540
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
521541
TARGETED_DEVICE_FAMILY = "1,2";
542+
USER_HEADER_SEARCH_PATHS = "";
522543
};
523544
name = Debug;
524545
};
@@ -562,6 +583,7 @@
562583
SDKROOT = iphoneos;
563584
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
564585
TARGETED_DEVICE_FAMILY = "1,2";
586+
USER_HEADER_SEARCH_PATHS = "";
565587
VALIDATE_PRODUCT = YES;
566588
};
567589
name = Release;
Binary file not shown.

RxSwift-Table-Collection1/RxSwift-Table-Collection/RxSwift-Bridging-Header.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@
1111

1212
//Libs使用cocoaPods集成
1313
#import "MJRefresh.h"
14-
#import "SVProgressHUD"
14+
#import "SVProgressHUD.h"
1515

1616
#endif /* RxSwift_Bridging_Header_h */
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//
2+
// ObservableObjectMapper.swift
3+
// RxSwiftMoyaDemo
4+
//
5+
// Created by iOS_Tian on 2017/9/29.
6+
// Copyright © 2017年 iOS_Tian. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import RxSwift
11+
import Moya
12+
import ObjectMapper
13+
14+
/*
15+
extension Observable {
16+
//1. 单个对象的处理
17+
public func mapObject<T: Mappable>(type: T.Type) -> Observable<T> {
18+
return self.map({ response in
19+
20+
//1-1. 如果response是一个字典,就用ObjectMapper映射这个字典
21+
guard let dict = response as? [String: Any] else {
22+
//1-2. 如果不是字典就抛出一个错误
23+
throw NetworkRequestState.jsonError
24+
}
25+
26+
//2. 返回模型数组
27+
return Mapper<T>().map(JSON: dict)!
28+
})
29+
}
30+
31+
//2. 对象数组的处理
32+
public func mapObjectArray<T: Mappable>(type: T.Type) -> Observable<[T]> {
33+
return self.map({ response in
34+
35+
//2-0. 先判断返回类型是不是一个对象
36+
guard let array = response as? [String: Any] else {
37+
throw NetworkRequestState.jsonError
38+
}
39+
40+
//2-1. 判断返回类型是不是一个对象
41+
guard let anchors = array["message"] as? [String: Any] else {
42+
throw NetworkRequestState.jsonError
43+
}
44+
45+
//2-1. 如果response是一个字典数组,就用ObjectMapper映射这个数组
46+
guard let dictArr = anchors["anchors"] as? [[String: Any]] else {
47+
//2-2. 如果不是字典就抛出一个错误
48+
throw NetworkRequestState.jsonError
49+
}
50+
51+
//3. 返回模型数组
52+
return Mapper<T>().mapArray(JSONArray: dictArr)
53+
})
54+
}
55+
}
56+
57+
58+
59+
//请求错误显示信息
60+
enum NetworkRequestState: String {
61+
case jsonError = "解析错误"
62+
case OtherError
63+
}
64+
65+
extension NetworkRequestState : Error {}
66+
*/
67+
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//
2+
// ReponseObjectMapper.swift
3+
// RxSwift-Table-Collection
4+
//
5+
// Created by iOS_Tian on 2017/9/29.
6+
// Copyright © 2017年 Quanjun. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import RxSwift
11+
import Moya
12+
import ObjectMapper
13+
14+
// MARK: - Json -> Model
15+
extension Response {
16+
// 1. 将Json解析为单个Model
17+
public func mapObject<T: BaseMappable>(_ type: T.Type) throws -> T {
18+
//1-1. 如果mapJSON()是一个字典,就用ObjectMapper映射这个字典
19+
guard let object = Mapper<T>().map(JSONObject: try mapJSON()) else {
20+
throw MoyaError.jsonMapping(self)
21+
}
22+
23+
//1-2. 返回映射的model
24+
return object
25+
}
26+
27+
28+
// 2. 将Json解析为多个Model,返回数组,对于不同的json格式需要对该方法进行修改
29+
public func mapObjectArray<T: BaseMappable>(_ type: T.Type) throws -> [T] {
30+
//2-0. 先判断返回类型是不是一个字典
31+
guard let array = try mapJSON() as? [String: Any] else {
32+
throw MoyaError.jsonMapping(self)
33+
}
34+
35+
//2-1. 判断返回类型是不是一个对象
36+
guard let anchors = array["message"] as? [String: Any] else {
37+
throw MoyaError.jsonMapping(self)
38+
}
39+
40+
//2-1. 如果response是一个字典数组,就用ObjectMapper映射这个数组
41+
guard let dictArr = anchors["anchors"] as? [[String: Any]] else {
42+
//2-2. 如果不是字典就抛出一个错误
43+
throw MoyaError.jsonMapping(self)
44+
}
45+
46+
//2-3. 返回model数组
47+
return Mapper<T>().mapArray(JSONArray: dictArr)
48+
}
49+
}
50+
51+
52+
// MARK: - Json -> Observable<Model>
53+
extension ObservableType where E == Response {
54+
// 1. 将Json解析为Observable<Model>(单个model)
55+
public func mapObject<T: BaseMappable>(_ type: T.Type) -> Observable<T> {
56+
return flatMap({ (response) -> Observable<T> in
57+
return Observable.just(try response.mapObject(T.self))
58+
})
59+
}
60+
61+
//2.将Json解析为Observable<[Model]>(数组)
62+
public func mapObjectArray<T: BaseMappable>(_ type: T.Type) -> Observable<[T]> {
63+
return flatMap({ (response) -> Observable<[T]> in
64+
return Observable.just(try response.mapObjectArray(T.self))
65+
})
66+
}
67+
}

RxSwift-Table-Collection1/RxSwift-Table-Collection/UICollectionView/Controllers/RxCollectionViewController.swift

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import UIKit
1010
import RxSwift
1111
import RxCocoa
12+
import RxDataSources
1213

1314

1415
fileprivate let kCollecCellID: String = "collecCell"
@@ -27,31 +28,58 @@ class RxCollectionViewController: UIViewController {
2728
//0.加载collectionViewCell
2829
collectionVIew.register(UINib(nibName: "RxCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: kCollecCellID)
2930

30-
//1.添加刷新
31-
collectionVIew.mj_header = MJRefreshNormalHeader(refreshingTarget: self, refreshingAction: #selector(collectionHeaderRefresh))
32-
collectionVIew.mj_footer = MJRefreshAutoNormalFooter(refreshingTarget: self, refreshingAction: #selector(collectionFooterRefresh))
31+
//1.设置代理
32+
//1-1. 绑定cell
33+
let dataSource = RxCollectionViewSectionedReloadDataSource<AnchorSection>()
34+
dataSource.configureCell = { ds, collectionView, indexPath, item in
35+
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: kCollecCellID, for: indexPath) as! RxCollectionViewCell
36+
cell.anchorModel = item
37+
return cell
38+
}
39+
40+
//2. 初始化请求
41+
let vmInput = AnchorViewModel.JunInput(category: .getNewList)
42+
let vmOutput = anchorVM.transform(input: vmInput)
43+
44+
//3. 添加刷新
45+
collectionVIew.mj_header = MJRefreshNormalHeader(refreshingBlock: {
46+
vmOutput.requestCommond.onNext(true)
47+
})
3348
collectionVIew.mj_header.beginRefreshing()
3449

35-
//2.给collectionView绑定数据
36-
anchorVM.heroVariable.asDriver().drive(collectionVIew.rx.items(cellIdentifier: kCollecCellID, cellType: RxCollectionViewCell.self)) { (_, anchor, cell) in
37-
cell.anchorModel = anchor
38-
}.addDisposableTo(bag)
50+
collectionVIew.mj_footer = MJRefreshAutoNormalFooter(refreshingBlock: {
51+
vmOutput.requestCommond.onNext(false)
52+
})
53+
54+
//4. 给collectionView绑定数据
55+
vmOutput.sections.asDriver().drive(collectionVIew.rx.items(dataSource: dataSource)).addDisposableTo(bag)
56+
57+
//5. 设置刷新状态
58+
vmOutput.refreshStatus.asObservable().subscribe(onNext: { (status) in
59+
switch status {
60+
case .beingHeaderRefresh:
61+
self.collectionVIew.mj_header.beginRefreshing()
62+
case .endHeaderRefresh:
63+
self.collectionVIew.mj_header.endRefreshing()
64+
case .beingFooterRefresh:
65+
self.collectionVIew.mj_footer.beginRefreshing()
66+
case .endFooterRefresh:
67+
self.collectionVIew.mj_footer.endRefreshing()
68+
case .noMoreData:
69+
self.collectionVIew.mj_footer.endRefreshingWithNoMoreData()
70+
default:
71+
break
72+
}
73+
}).addDisposableTo(bag)
74+
3975

40-
// 3.监听collectionView的点击
76+
77+
// 6.监听collectionView的点击
4178
collectionVIew.rx.modelSelected(AnchorModel.self).subscribe(onNext: { (model) in
4279
print(model.name)
4380
}).addDisposableTo(bag)
4481
}
4582

4683

47-
//下拉刷新
48-
@objc fileprivate func collectionHeaderRefresh(){
49-
50-
}
51-
52-
//上拉加载
53-
@objc fileprivate func collectionFooterRefresh(){
54-
55-
}
5684

5785
}

RxSwift-Table-Collection1/RxSwift-Table-Collection/UICollectionView/Model/AnchorModel.swift

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,43 @@
77
//
88

99
import UIKit
10+
import ObjectMapper
11+
import RxDataSources
1012

11-
class AnchorModel: NSObject {
13+
class AnchorModel: Mappable {
1214

13-
var roomid : Int = 0
14-
var name : String = ""
15-
var pic51 : String = ""
16-
var pic74 : String = ""
17-
var live : Int = 0
18-
var push : Int = 0
19-
var focus : Int = 0
15+
var name = ""
16+
var pic51 = ""
17+
var pic74 = ""
18+
var live = 0
19+
var push = 0
20+
var focus = 0
2021

21-
var isEvenIndex : Bool = false
22+
required init?(map: Map) {
23+
24+
}
25+
26+
func mapping(map: Map) {
27+
name <- map["name"]
28+
pic51 <- map["pic51"]
29+
pic74 <- map["pic74"]
30+
live <- map["live"]
31+
push <- map["push"]
32+
focus <- map["focus"]
33+
}
34+
}
35+
2236

37+
//MARK: SectionModel
38+
struct AnchorSection {
39+
var items: [Item]
2340

24-
init(dic : [String : Any]) {
25-
super.init()
26-
27-
name = dic["name"] as? String ?? ""
28-
pic51 = dic["pic51"] as? String ?? ""
29-
pic74 = dic["pic74"] as? String ?? ""
30-
focus = dic["focus"] as? Int ?? 0
41+
}
3142

43+
extension AnchorSection: SectionModelType {
44+
typealias Item = AnchorModel
45+
init(original: AnchorSection, items: [AnchorSection.Item]) {
46+
self = original
47+
self.items = items
3248
}
3349
}

0 commit comments

Comments
 (0)