前言
Moya是一个基于Alamofire开发的,轻量级的Swift网络层。Moya的可扩展性非常强,可以方便的RXSwift,PromiseKit和ObjectMapper结合。
如果你的项目刚刚搭建,并且是纯Swift的,非常推荐以Moya为核心去搭建你的网络层。另外,如果你对Alamofire的源码感兴趣,推荐我之前的一篇博客:
Moya除了依赖Alamofire,还依赖Result。Result用一种枚举的方式提供函数处理结果:
.success(let data)
// 成功,关联值是数据.falure(let error)
// 失败, 关联值是错误原因
本文的讲解顺序:Moya的实现原理 -> Moya的设计理念 -> Moya与RxSwift,ObjectMapper一起工作
–
接口
分析任何代码都是从它的接口开始的。
我们先来看看通过Moya如何去写一个网络API请求。Moya中,通过协议TargetType来表示这是一个API请求。
协议要求提供以下属性,
public protocol TargetType {
var baseURL: URL { get }
var path: String { get }
var method: Moya.Method { get }
var parameters: [String: Any]? { get } //参数
var parameterEncoding: ParameterEncoding { get } //编码方式
var sampleData: Data { get }//stub数据
var task: Task { get }//请求类型,Data/Downlaod/Upload
var validate: Bool { get } //是否需要对返回值验证,默认值false
}
通过枚举来管理一组API,比如
public enum GitHub {
case zen
case userProfile(String)
}
extension GitHub: TargetType {
public var baseURL: URL { return URL(string: "https://api.github.com")! }
public var path: String {
switch self {
case .zen:
return "/zen"
case .userProfile(let name):
return "/users/\(name.urlEscaped)"
}
}
//....
}
当然也可以让你的Class/Stuct来实现TargetType协议,使用枚举可以方便的管理一组API,优点是方便复用baseURL,method等,缺点是不得不写大量的Switch语句
然后,在进行API请求的时候,要创建MoyaProvider
,接着调用Request方法进行实际的请求
let provider = MoyaProvider<GitHub>()
provider.request(.zen) { result in
if case let .success(response) = result {
}
}
可以看到,Moya通过协议来定义一个网络请求,并且属性都是只读的。协议意味着是依赖于抽象,而不是具体的实现,这样更易控制藕合,并且容易扩展;只读的意味着不可变状态,不可变状态会让你的代码行为可预测。
模块
通过功能划分,Moya大致分为几个模块
- Request,包括TargetType,Endpoint,Cancellable集中类型
- Provider,网络请求的枢纽,Provider会把
TargetType
转换成Endpoint
再转换成URLRequest
交给Alamofire去实际执行 - Response,回调给上层的数据结构,支持
filter
,mapJSON
等方法 - Alamofire封装,通过桥接的方式对上层隐藏alamofire的细节
Plguins,插件。moya提供了插件来给给外部。包括四个方法,这里知道方法就好,后文会具体的讲解插件的方法在何时工作。
public protocol PluginType { func prepare(_ request: URLRequest, target: TargetType) -> URLRequest func willSend(_ request: RequestType, target: TargetType) func didReceive(_ result: Result<Moya.Response, MoyaError>, target: TargetType) func process(_ result: Result<Moya.Response, MoyaError>, target: TargetType) -> Result<Moya.Response, MoyaError> }
原理
为了更好的讲解Moya的处理流程,我画了一张图(用Sketch画的):
第一眼看到这张图的时候,你肯定是困惑的,我们来一点点讲解图中的过程。通过上文的讲解我们知道,Provider这个类是网络请求的枢纽,它接受一个TargetType(请求),并且通过闭包的方式给上层回调。
那么,我们来看看Provider的初始化方法:
public init(endpointClosure: @escaping Endpoint