通过 Moya + RxSwift + Argo 完成网络请求
作者:@请叫我汪二 授权本站转载。
最近在新项目中尝试使用 Moya+RxSwift+Argo 进行网络请求和解析,感觉还阔以,再来给大家安利一波。
Moya
Moya 是一个基于 Alamofire 的更高层网络请求封装,深入学习请参见官方文档:Moya/Docs。
使用 Moya 之后网络请求一般长了这样:
1
2
3
4
5
|
provider.request(.UserProfile("ashfurrow")) { (data, statusCode, response, error) in
if let data = data {
// do something with the data
}
}
|
Moya 提供了很多不错的特性,其中我感觉最棒的是 stub ,配合 sampleData 分分钟就完成了单元测试:
1
|
private let provider = MoyaProvider(stubClosure: MoyaProvider.ImmediatelyStub)
|
注意这里的 MoyaProvider.ImmediatelyStub ,我原以为它是个枚举类型,看了 MoyaProvider 定义发现这里应该传个closure ,看了 ImmediatelyStub 的定义发现原来它是个类方法:
1
2
3
4
5
6
7
8
9
|
public typealias StubClosure = Target -> Moya.StubBehavior
override public init(stubClosure: StubClosure = MoyaProvider.NeverStub, ...) {
}
public final class func ImmediatelyStub(_: Target) -> Moya.StubBehavior {
return .Immediate
}
|
如果想打印每次请求的参数,在组装 endpoint 的时候打印即可:
1
2
3
4
5
6
7
8
|
private func endpointMapping(target: Target) -> Endpoint {
if let parameters = target.parameters {
log.verbose("\(parameters)")
}
return MoyaProvider.DefaultEndpointMapping(target)
}
private let provider = RxMoyaProvider(endpointClosure: endpointMapping)
|
RxSwift
RxSwift 前面强行安利过两波,在此不再赘述啦,Moya 本身提供了 RxSwift 扩展,可以无缝衔接 RxSwift 和ReactiveCocoa ,于是打开方式变成了这样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
private let provider = RxMoyaProvider()
private var disposeBag = DisposeBag()
extension ItemAPI {
static func getNewItems(completion: [Item] -> Void) {
disposeBag = DisposeBag()
provider
.request(.GetItems())
.subscribe(
onNext: { items in
completion(items)
}
)
.addDisposableTo(disposeBag)
}
}
|
Moya 的核心开发者、同时也是 Artsy 的成员:Ash Furrow, 在 AltConf 做过一次 《Functional Reactive Awesomeness With Swift》 的分享,推荐大家看一下,很可爱的!
Argo
Argo 是 thoughtbot 开源的函数式 JSON 解析转换库。说到 thoughtbot 就不得不提他司关于 JSON 解析质量很高的一系列文章:
Efficient JSON in Swift with Functional Concepts and Generics
Real World JSON Parsing with Swift
Parsing Embedded JSON and Arrays in Swift
Functional Swift for Dealing with Optional Values
Argo 基本上就是沿着这些文章的思路写出来的,相关的库还有 Runes 和 Curry。
使用 Argo 做 JSON 解析很有意思,大致长这样:
1
2
3
4
5
6
7
8
9
10
11
12
|
struct Item {
let id: String
let url: String
}
extension Item: Decodable {
static func decode(j: JSON) -> Decoded {
return curry(Item.init)
j <| "id"
j <| "url"
}
}
|
至于这其中各种符号的缘由,在几篇博客中都有讲解,还是挺有意思滴。
All
说完这三者,如何把它们串起来呢?Emergence 中的 Observable/Networking 给了我们答案。稍微整理后如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
enum ORMError : ErrorType {
case ORMNoRepresentor
case ORMNotSuccessfulHTTP
case ORMNoData
case ORMCouldNotMakeObjectError
}
extension Observable {
private func resultFromJSON(object:[String: AnyObject], classType: T.Type) -> T? {
let decoded = classType.decode(JSON.parse(object))
switch decoded {
case .Success(let result):
return result as? T
case .Failure(let error):
log.error("\(error)")
return nil
}
}
func mapSuccessfulHTTPToObject(type: T.Type) -> Observable {
return map { representor in
guard let response = representor as? MoyaResponse else {
throw ORMError.ORMNoRepresentor
}
guard ((200...209) ~= response.statusCode) else {
if let json = try? NSJSONSerialization.JSONObjectWithData(response.data, options: .AllowFragments) as? [String: AnyObject] {
log.error("Got error message: \(json)")
}
throw ORMError.ORMNotSuccessfulHTTP
}
do {
guard let json = try NSJSONSerialization.JSONObjectWithData(response.data, options: .AllowFragments) as? [String: AnyObject] else {
throw ORMError.ORMCouldNotMakeObjectError
}
return self.resultFromJSON(json, classType:type)!
} catch {
throw ORMError.ORMCouldNotMakeObjectError
}
}
}
func mapSuccessfulHTTPToObjectArray(type: T.Type) -> Observable {
return map { response in
guard let response = response as? MoyaResponse else {
throw ORMError.ORMNoRepresentor
}
// Allow successful HTTP codes
guard ((200...209) ~= response.statusCode) else {
if let json = try? NSJSONSerialization.JSONObjectWithData(response.data, options: .AllowFragments) as? [String: AnyObject] {
log.error("Got error message: \(json)")
}
throw ORMError.ORMNotSuccessfulHTTP
}
do {
guard let json = try NSJSONSerialization.JSONObjectWithData(response.data, options: .AllowFragments) as? [[String : AnyObject]] else {
throw ORMError.ORMCouldNotMakeObjectError
}
// Objects are not guaranteed, thus cannot directly map.
var objects = [T]()
for dict in json {
if let obj = self.resultFromJSON(dict, classType:type) {
objects.append(obj)
}
}
return objects
} catch {
throw ORMError.ORMCouldNotMakeObjectError
}
}
}
}
|
这样在调用的时候就很舒服了,以前面的 Item 为例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
private let provider = RxMoyaProvider()
private var disposeBag = DisposeBag()
extension ItemAPI {
static func getNewItems(records:[Record] = [], needCount: Int, completion: [Item] -> Void) {
disposeBag = DisposeBag()
provider
.request(.AddRecords(records, needCount))
.mapSuccessfulHTTPToObjectArray(Item)
.subscribe(
onNext: { items in
completion(items)
}
)
.addDisposableTo(disposeBag)
}
}
|
一个 mapSuccessfulHTTPToObjectArray 方法,直接将 JSON 字符串转换成了 Item 对象,并且传入了后面的数据流中,所以在 onNext 订阅的时候传入的就是 [Item] 数据,并且这个转换过程还是可以复用的,且适用于所有网络请求中 JSON 和 Model 的转换。爽就一个字,我只说一次。
爽!
Next
匆匆读了一点 Emergence 和 Eidolon 的项目源码,没有深入不过已经受益匪浅。通过 bundle 管理 id 和 key 直接解决了我当初纠结已久的『完整项目开源如何优雅地保留 git 记录且保护项目隐私』的问题,还有 Moya/RxSwift 和Moya/ReactiveCocoa 这种子模块化处理也在共有模块管理这个问题上给了我一些启发。
真是很喜欢 Artsy 这样的团队,大家都一起做着自己喜欢的事情,还能站着把钱赚了。
所幸的是我也可以这样做自己喜欢的事情了,不过不赚钱。具体状况后面单独开一篇闲扯扯。
碎告。
参考资料:
RxSwift
Moya
Argo
Emergence
Eidolon
Efficient JSON in Swift with Functional Concepts and Generics
Real World JSON Parsing with Swift
Parsing Embedded JSON and Arrays in Swift
Functional Swift for Dealing with Optional Values
转载于:https://my.oschina.net/hejunbinlan/blog/602028
通过 Moya + RxSwift + Argo 完成网络请求相关推荐
- Moya+RxSwift+HandyJson 实现网络请求及模型转换
CocoaPods集成 pod 'RxCocoa' pod 'RxSwift'pod 'Moya/RxSwift' pod 'HandyJSON' Moya简单使用 定义枚举,存储网络请求 // 1 ...
- Moya+ RxSwift+HandyJSON 优雅处理网络请求
前言 在移动端的开发中,网络请求是必不可少的.之前写过Alamofire的简单使用,但是一般开发中都会对这些第三库封装,然后使用,之前自己封装的demo也是借鉴了一些Moya的设计思路.今天就介绍一下 ...
- Swift 掌控Moya的网络请求、数据解析与缓存
Moya 在Swift开发中起着重要的网络交互作用,但是还有不如之处,比如网络不可用时,返回的 Response 为 nil,这时还得去解析相应的 Error Codable 可以帮助我们快速的解析数 ...
- Swift 网络请求 Moya+RxSwift
Swift中优雅的网络请求 官方github // 1.定一个enum enum MyService {xxxxcase showUser(id: Int)xxx }// 2.扩展这个enum,符合 ...
- 项目剖析03-swift 网络请求Moya+HandyJSON+RxSwift
项目第一版网络框架用的是siesta,它的缓存与自动刷新确实很好用而且代码很简洁,但是在文件的上传与下载以及对返回类型需要精确匹配要求这方面就很不友好,所以在第二版的我选择了Moya,它是一个网络抽象 ...
- Swift 优雅的网络请求Moya
Moya使用demo Moya 面向协议 Moya的模块组成 代码demo Controller中使用 Moya Moya是一个网络抽象层,它在底层将Alamofire进行封装,对外提供更简洁的接口供 ...
- iOS 【如何写出最简洁优雅的网络封装 Moya + RxSwift】
前言 Why Moya ? Alamofire可能是iOS Swift中最常用的HTTP networking library,用Alamofire可以抽象出NSURLSession和其中很多繁琐的细 ...
- rxswift 网络请求_使用RxSwift将身份验证请求链接到多个服务
rxswift 网络请求 At a company that I have worked in the past, a high-traffic online classifieds, the bac ...
- Swift 网络请求库Moya的使用
Moya是Swift中的网络库Alamofire的二次封装,Alamofire本身使用起来是很简单方便的,例子如下: func loadData(){var param = [String:Strin ...
最新文章
- html5网页仿写,纯CSS代码模仿绘制蚂蚁庄园页面
- JVM源码---教你傻瓜式编译openjdk7(JAVA虚拟机爱好者必看)
- Linux基本管理七大流程
- Objective-C 2.0 with Cocoa Foundation--- 5,Class类型,选择器Selector以及函数指针
- java_version干什么的_java类中serialVersionUID的作用及其使用
- Vmware中RedHat命令行和图形界面切换
- JDK的问题:用C启动虚拟机跟java运行结果有差异
- 单代号网络图计算例题_海量优质网络图模板,轻巧实用的国产作图神器
- 手游入门必备基础知识
- 摩天轮社区_摩天轮:基于真实地理位置游戏
- 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
- 【优化求解】基于收敛因子和黄金正弦指引机制的蝴蝶优化算法求解单目标优化问题matlab代码(AGSABOA)
- Mvp+OkHttp+XRecyclerView------上拉加载下拉刷新
- 企业CMS网站建设第二课:CMS模版开发——CMS基础设置与栏目管理
- c# 两个日期之间的比较与两个日期相差天数计算
- pyinstaller打包前后os.path.abspath(__file__)和os.path.realpath(sys.executable)的区别
- 微软新编程字体开源,用着一不小心就骂人了
- 边界提取(Region的边界提取)
- 期货和股票平仓时成本计价的区别
- sed 匹配非常规空格[[:space:]]+