Moya 是一个基于Alamofire的 面向协议 插件化的 网络库,调用者可以通过实现TargetType协议和方便的发起网络调用,而且可以根据不同的需要定制各种插件进行初始化。
但是在实际使用过程中仍有一些个问题
1 TargetType 协议变量太多,调用方实际只主要关心 task, path 这两个, BaseUrl不应该暴露给调用方,这些都可以通过扩展TargetType 来实现,但是若想加入其它功能,比方说加入缓存功能,加入token,或者加入大量公共参数,这些该如何实现,怎么实现比较好?
2 Moya 网络返回的是Moya.Response 类型的数据,实际开发中大量使用自定义的Struct 作为 数据类型,虽然有ObjectMapper 可以很方便的做数据转换,但每次都要在闭包里做一次转换,可以直接返回一个Struct对象不是更好吗?
解决办法
1 继承TargetType, 创建一个新的Target协议, 加入自定义参数,同时隐藏不必要参数,比如想加入缓存功能,
1 先定义缓存协议
publicenumRequestCachePolicy{
/// 忽略缓存,仅加载网络数据
casereloadIgnoringLocalCacheData
/// 只加载缓存数据
caseretutnCacheDataDontLoad
/// 先加载缓存然后网络数据
caseretutnCacheDataThenLoad
}
public protocol CacheType {
// 是否需要缓存
varneedCache:Bool{get}
// 缓存资源的标示
varcacheId: () ->String{get}
// 加载缓存策略
varcachePolicy:RequestCachePolicy{get}
}
2 创建新的TargetType, 并且加入自定义参数,同时
public protocol XLTargetType: TargetType, CacheType, AccessTokenAuthorizable{
/// 具体业务参数
varparameters: [String:Any]? {get}
}
3 重写MoayProvider 支持缓存功能
详见 Github
2 第二个问题,有三个思路
1 扩展Moya.Response类型,增加转换函数,这是基础,每次请求后多家一行转换函数
funcmapCommonModel()throws->T{
do{
letjsonObj = tryJSONSerialization.jsonObject(with:data, options: .allowFragments)
letobject =Mapper().map(JSONObject: jsonObj)
ifobject ==nil{
throwYLError.mapNilError
}
returnobject!
}catchYLError.mapNilError {
throwYLError.mapNilError
}catch{
throwYLError.responseError
}
}
2 将返回的数据类型做成 associatedtype 定义在新建的TargetType中,并重写MoyaProvider,这样请求直接返回的就是关联类型指定的数据类型, 但这样会造成另外一个问题:没有办法批量写Api代码,毕竟每个TargetType协议只支持一个associatedtype
public protocol YLTargetType: TargetType, CacheType, AccessTokenAuthorizable{
/// 返回数据类型, 这种写法理论上没问题,但实际用起来很麻烦,没办法批量组织api
associatedtyperesponseModelType:Mappable
/// 具体业务参数
varparameters: [String:Any]? {get}
}
// 调用
let provider = DataProvider()
let sequence1 = provider.rx.requestModel(.home)
let sequence2 = provider.rx.requestResult(.home)
3 将数据类型做成provider.request() 函数的泛型,这样也可以直接返回数据类型, 这也是最好的一种
publicprotocolXLProviderType:AnyObject{
associatedtype Target: XLTargetType
funcrequest(_target:Target, callbackQueue:DispatchQueue?, progress:Moya.ProgressBlock?, completion:@escaping(_result:Result,_isCache:Bool) ->Void) ->Cancellable
}
// 调用
let provider = XLProvider()
let userSequence = provider.rx.requestResult(.user) as Observable>
详见Github
最后
第三方虽然好用,但是对第三方包装一层仍然是必要的,
1 万一没有,发生AF2.0 到 AF3.0哪样的重大变动,那就炸了
2 第三方通用性太好,但不贴近实际项目,根绝实际需求自定制一下,对于开发者会友好的多,
3 面向协议和插件化是网络库最好的选择, 关于插件没有细说,代码里有
网友评论