什么是Moya?
对于iOS的开发人员来说,一般我们的网络请求是使用Alamofire来抽象的访问URLSession,为了更好的管理网络请求,一般的做法就是封装一个网络抽象层。但是一般的专有网络框架会出现一下问题:
编写新项目很困难
维护现有的项目很困难
编写单元测试很困难
比如我刚开始使用swift的网络框架的时候,因为公司的接口是多人开发的没有太好的规范,所以写出来的接口五花八门,我就需要根据不同的人的接口写出不一样的网络请求,这样就让网络请求的工具类看起来特别的乱,项目维护起来也特别的难。在项目上线之后,我就一直想要解决这个问题,查看了很多资料,找到了Moya.
Moya的基本思想是,他提供给我们一个网络抽象层,他充分的封装且实际调用了Alamofire,他是用一份方式来抽象URL和parameters
Moya的一些特色功能是:
对正确的API端口访问进行编译时的检查
使用关联的枚举定义不同的端点,这样维护和查找使用的时候更加的清晰
把test stub作为一等公民,所以单元测试超级简单
利于Swift 编译器来防止与配置网络请求相关的运行时错误 .
为网络请求提供 Swift风格API/抽象.
提供一个API,它可以非常容易来代理(stub)网络请求.
提供一个基本的响应解析,同时也为其他库公开定制点来提供帮助.
为API提供 (可选的) RxSwift / ReactiveSwift 扩展.
通过为自定义行为提供周到且易于使用的扩展的点来避免有漏洞的抽象。
赞同明确定义的行为胜过默认实现
上述来自Moya!!!
通俗的自我理解就是,你不需要自己在去封装网络层来管理Alamofire,你只需要使用Moya一个高效的网络层,让他来管理网络请求。
基本用法
使用Moya其实还是比较简单的。
第一步:为你所用的API目标创建一个enum,这个enum用来在target编译的时候提供实现的具体细节,在这里可以看到请求所需要的参数,这个enum必须遵循TargetType类型,在同一文件中通过扩展实现。
第二步:通过扩展遵循TargetType类型,实现方法。
这样TargetType协议保证每个enum的值被转化成一个完整的requst,每个requst被分割成baseURL和Path,定义了请求方式,已经参数和参数编码的test
这样就已经为基本的API网络层添加了基本的信息。默认的情况下,Moya回将给定的部分合并成一个完整的请求。
第三步发送请求:
原理介绍
Moya的通过Provider这个类来完成所以网络的请求以及响应。在这里从发起请求和响应处理2方面说一下
Provider的初始化方法
public init(endpointClosure: @escaping EndpointClosure = MoyaProvider.defaultEndpointMapping,
requestClosure: @escaping RequestClosure = MoyaProvider.defaultRequestMapping,
stubClosure: @escaping StubClosure = MoyaProvider.neverStub,
manager: Manager = MoyaProvider.defaultAlamofireManager(),
plugins: [PluginType] = [],
trackInflights: Bool = false) {
//...
}
初始化的时候的几个参数:
endpointClosure 作用是把TargetType转换成EndPoint,EndPoint是Moya网络请求的一个中间态。
requestClosure 作用是把Endpoint转换成URLRequest
stubClosure 是用来桩测试的,也就是模拟服务端假数据,这里先不管。
manager,实际请求的Alamofire的SessionManager
plugins, 插件
trackInflights,是否要跟踪重复网络请求
如何这些使用默认的,有一个简单的方法。
Request的实现
Moya中请求是Provider管理者,通过如图方式进行转换的。
Providers 映射 Targets 成 Endpoints, 然后映射 Endpoints 到实际的网络请求。
Endpoints
endPoint是Moya的半个内部结构,它最终被用来生成网络请求。endpoint存储了网络请求的相关数据。
url.
HTTP 方法 (GET, POST, etc).
HTTP 请求头.
Task 用来区别 upload, download 和 request.
sample response (为单元测试).
我们可以根据实际需要自定义endpoint闭包来转换,并且在初始化的时候传递给endpointClosure.
例如:
这种就是在创建一个单元测试中返回一个非200HTTP状态的测试Provider,或者您需要改变task, method, url, headers 或者 sampleResponse。 比如, 我们可能希望将应用程序名称设置到HTTP头字段中,从而用于服务器端分析。您可以为部分或者所有的endpoint提供附加参数。
假设 MyTarget 除了实际执行身份验证的值之外,其他的所有值都需要有一个身份证令牌,我们可以构造一个类似如下面的 endpointClosure 。
Request 映射
紧接着在某一时刻,Endpoint 必须被转化成 URLRequest 从而给到 Alamofire。 这就是 requestClosure 参数的作用.
requestClosure有默认的参数,是可选的。这个闭包接受一个EndPoint实例对象并负责包代表EndPoint的requst作为RequestResultClosure闭包。这个闭包在实际的编辑请求对象是非常有用。比如:
1、禁用所以请求的cookie
2、输出网络请求的log日志
响应(ReSponse)
Moya并没有对Response进行特殊处理,仅仅是把Alamofire层面返回的数据封装成Moya.Response,然后再调用convertResponseToResult进一步封装成Result类型交给上层。
不过Moya提供了几种转换方法:
mapImage()尝试把响应数据转化为UIImage实例 如果不成功将产生一个错误。
mapJSON()尝试把响应数据映射成一个JSON对象,如果不成功将产生一个错误。
mapString()把响应数据转化成一个字符串,如果不成功将产生一个错误。
mapString(atKeyPath:)尝试把响应数据的key Path映射成一个字符串,如果不成功将产生一个错误。
我们可以直接拿到数据进行处理。
在这里盗取一张图大家可以看看。流程画的很好。
Moya插件
moya有一个特别好用的插件Plugin,他可以让你在网络请求的的时候用来编辑请求,响应以及完成副作用。
moya提供了4中插件有需要的自己看看。
AccessTokenPlugin OAuth的Token验证
NetworkActivityPlugin 网络请求状态
NetworkLoggerPlugin 网络日志
附上一个我写的Moya和objectMapper封装的demo。
https://github.com/nanaLxs/LearnSwiftDemo 地址传送带:Moya+objectMapperdemo
大家互相学习了。