通过 Moya+RxSwift+Argo 完成网络请求
2017-06-29 15:29
369 查看
https://blog.callmewhy.com/2015/11/01/moya-rxswift-argo-lets-go/
最近在新项目中尝试使用 Moya+RxSwift+Argo 进行网络请求和解析,感觉还阔以,再来给大家安利一波。
使用
注意这里的
如果想打印每次请求的参数,在组装
Furrow, 在 AltConf 做过一次 《Functional
Reactive Awesomeness With Swift》 的分享,推荐大家看一下,很可爱的!
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
使用
至于这其中各种符号的缘由,在几篇博客中都有讲解,还是挺有意思滴。
说完这三者,如何把它们串起来呢?Emergence 中的 Observable/Networking 给了我们答案。稍微整理后如下:
这样在调用的时候就很舒服了,以前面的
一个
爽!
匆匆读了一点 Emergence 和 Eidolon 的项目源码,没有深入不过已经受益匪浅。通过
bundle 管理 id 和 key 直接解决了我当初纠结已久的『完整项目开源如何优雅地保留 git 记录且保护项目隐私』的问题,还有
真是很喜欢 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
最近在新项目中尝试使用 Moya+RxSwift+Argo 进行网络请求和解析,感觉还阔以,再来给大家安利一波。
Moya
Moya是一个基于
Alamofire的更高层网络请求封装,深入学习请参见官方文档:Moya/Docs。
使用
Moya之后网络请求一般长了这样:
provider.request(.UserProfile("ashfurrow")) { (data, statusCode, response, error) in if let data = data { // do something with the data }} |
Moya提供了很多不错的特性,其中我感觉最棒的是
stub,配合
sampleData分分钟就完成了单元测试:
private let provider = MoyaProvider<ItemAPI>(stubClosure: MoyaProvider.ImmediatelyStub) |
MoyaProvider.ImmediatelyStub,我原以为它是个枚举类型,看了
MoyaProvider定义发现这里应该传个
closure,看了
ImmediatelyStub的定义发现原来它是个类方法:
public typealias StubClosure = Target -> Moya.StubBehavioroverride public init(stubClosure: StubClosure = MoyaProvider.NeverStub, ...) {}public final class func ImmediatelyStub(_: Target) -> Moya.StubBehavior { return .Immediate} |
endpoint的时候打印即可:
private func endpointMapping<Target: MoyaTarget>(target: Target) -> Endpoint<Target> { if let parameters = target.parameters { log.verbose("\(parameters)") } return MoyaProvider.DefaultEndpointMapping(target)}private let provider = RxMoyaProvider<ItemAPI>(endpointClosure: endpointMapping) |
RxSwift
RxSwift前面强行安利过两波,在此不再赘述啦,
Moya本身提供了
RxSwift扩展,可以无缝衔接
RxSwift和
ReactiveCocoa,于是打开方式变成了这样:
private let provider = RxMoyaProvider<ItemAPI>()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解析很有意思,大致长这样:
struct Item { let id: String let url: String}extension Item: Decodable { static func decode(j: JSON) -> Decoded<Item> { return curry(Item.init) <^> j <| "id" <*> j <| "url" }} |
All
说完这三者,如何把它们串起来呢?Emergence 中的 Observable/Networking 给了我们答案。稍微整理后如下:enum ORMError : ErrorType { case ORMNoRepresentor case ORMNotSuccessfulHTTP case ORMNoData case ORMCouldNotMakeObjectError}extension Observable { private func resultFromJSON<T: Decodable>(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<T: Decodable>(type: T.Type) -> Observable<T> { 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<T: Decodable>(type: T.Type) -> Observable<[T]> { 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为例:
private let provider = RxMoyaProvider<ItemAPI>()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
相关文章推荐
- moya + RxSwift 进行网络请求
- 用 RxSwift + Moya 写出优雅的网络请求代码
- Moya+ RxSwift+HandyJSON 优雅处理网络请求
- iOS 【如何写出最简洁优雅的网络封装 Moya + RxSwift】
- 浅谈RxSwift 网络请求
- Swift - 使用SwiftHTTP通过HTTPS进行网络请求,及证书的使用
- Swift - 使用Alamofire通过HTTPS进行网络请求,及证书的使用
- Swift网络请求于数据解析简单封装
- 使用AsyncHttpClient框架来完成网络数据的请求
- Ajax发送同步请求给Spring,通过controller处理完成后如何返回响应
- Swift网络开发-在DownloadTask完成前获取Resposne
- 通过网络请求获取数据时,如果立即使用就会报错:数据为空
- Alamofire网络库基础教程:使用 Alamofire 轻松实现 Swift 网络请求
- [Swift 工作tips] 之 使用Alamofire做网络请求时设置请求超时(timeout)时间
- Alamofire网络库基础教程:使用 Alamofire 轻松实现 Swift 网络请求
- swift网络数据请求方法
- Swift之网络编程-请求缓存
- Swift之网络请求
- Alamofire网络库基础教程:使用 Alamofire 轻松实现 Swift 网络请求