Moya架构图
CocoaPods集成
pod 'RxCocoa'
pod 'RxSwift'
pod 'Moya/RxSwift'
pod 'HandyJSON'
Moya简单使用
1.定义枚举,存储网络请求
// 定义一个枚举,存放我们的网络请求
enum MemberApi {
case login(username:String,password:String,token:String)
}
2. 实现moya的TargetType协议
extension MemberApi:TargetType{
//api 接口基地址
var baseURL: URL {
return URL.init(string: BaseURL)!
}
//请求路径
var path:String{
switch self {
case .login(username: _, password:_ , token:_):
return "login/accountLogin"
}
}
var headers: [String: String]{
return nil;
}
//请求的参数
var parameters: [String: Any]{
switch self {
case .login(username: let userName, password: let pwd, token: let token):
return ["account":userName,"pwd":pwd,"deviceToken":token];
}
}
///请求方式
var method: Moya.Method {
switch self {
case .login(username: _, password: _, token: _):
return .post;
}
}
/// The method used for parameter encoding.
var parameterEncoding: ParameterEncoding {
return URLEncoding.default
}
/// Provides stub data for use in testing.
var sampleData: Data {
return "".data(using: String.Encoding.utf8)!
}
//MARK:task type
var task: Task {
return .requestPlain
}
var validate: Bool {
return false
}
}
3. 发起网络请求
let provider = MoyaProvider<MemberApi>();
provider.request(.login(username: "haha", password: "123456", token: "qwe")) { (result) in
if result.error == nil{
LLog(result.value);
}
}
模型转换
首先, 我们需要处理Moya请求返回Moya.Response对象, 在返回给客户端时我们需要将Moya.Response映射成相应的模型对象。
其次, 我们希望使用RxSwift的链式写法来完成字典到模型的转换。
基于如上两点: 我们需要做如下两步处理。
1.扩展RxSwift 的 Observable 协议给其添加mapModel方法,传入要映射的模型类型
2.需要将Moya.Response对象映射成相应的模型对象,这里配合使用HandyJSON库
代码如下:
///定义在处理过程中可能出现的Error
enum RxSwiftMoyaError: String {
case ParseJSONError ///解析json时出错
case OtherError ///其他错误
case ResponseError ///返回的结果有错
case RequestFailedError ///请求返回错误 (根据请求码判断)
}
///让其实现Swift.Error 协议
extension RxSwiftMoyaError: Swift.Error { }
///扩展 RxSwift的Observable协议,添加mapModel方法
extension Observable {
func mapModel<T: HandyJSON>(_ type: T.Type) throws -> Observable<T> {
return map { response in
///判断Response类型
guard let response = response asMoya.Response else {
throw RxSwiftMoyaError.ResponseError
}
///判断请求码
guard (200...209) ~= response.statusCode else {
throw RxSwiftMoyaError.RequestFailedError
}
///转json
guard let json = tryJSONSerialization.jsonObject(with: response.data, options: JSONSerialization.ReadingOptions.init(rawValue: 0)) as! [String: Any] else {
throw RxSwiftMoyaError.ResponseError
}
///使用HandyJSON库,映射成指定模型
let object = JSONDeserializer<T>.deserializeFrom(dict: json)
guard let model = object else {
throw RxSwiftMoyaError.ParseJSONError
}
return model
}
}
}
使用:
///初始化一个MoyaProvider, 其中MemberApi为使用了TargetType协议的enum枚举
let mp = MoyaProvider<MemeberApi>()
let ob = mp
.rx.request(type) /// rx.request 为Moya/RxSwift 库中提供的扩展实现,返回的是一个Single类型
.asObservable() ///需要使用asObservable将Single类型转成Observable
.mapModel(UserInfo.self) ///将请求返回结果进行映射
网络请求的处理过程大致如上,代码中只有有网络请求的地方就会有如下代码,所以这块代码的调用我们再把它封装一下。
final class NetworkTools {
static func request<H: HandyJSON, T: TargetType>(_ type:T, _ model: H.Type) -> Observable<H> {
let mp = MoyaProvider<T>()
let ob = mp
.rx.request(type) ///type 实现T类型协议的具体对象
.asObservable()
.mapModel(model)
return ob
}
}
///使用
NetworkTools.request(MemberApi.login(username: "haha", password: "123456", token: "qwe"), UserInfo.self)
.subscribe(onNext:{ ///订阅
})
最后
针对网络层的封装,在如下的Demo中又做了演进,如果感兴趣,请移步至项目 TestProject 中查看