Advanced usage - use MultiTarget for multiple targets using the same Provider(高级用法--使用MultiTarget(为多个target使用同样的Provider)
当你有很多个endpoints时,你可能会得到一个很长的provider并且在几百个case里面切换.当然,你可以把这些逻辑分割到多个target中,但你不得不使用多个providers.这会使你的app逻辑复杂化,如果你想为每个provider使用相同的plugins/closures,需要额外的工作来管理它.然而,我们可以使用MutiTarget这个内置枚举,它可以很容易的使用,而且能帮我们解决上面的问题.
首先,我们定义一个将使用多个target的provider
let provider = MoyaProvider<MultiTarget>()
然后把请求
provider.request(.zen) { result in
// do something with `result`
}
替换成
provider.request(MultiTarget(GitHub.zen)) { result in
// do something with `result`
}
改造完毕!相当的简单.如果你有很多想分割的endpoint---这将是一个完美的解决方法.如果你想看这个API,请查看Demo,它有两个target:一个是Demo(使用Moya的基本形式),一个是DemoMultiTarget(使用编辑版的MutiTarget形式)
Multiple targets when using associatedtype(在Mutiple target中使用关联类型)
当调用一个网络请求时,Moya可以让你静态的验证参数。你有可能想扩展Moya的TargetType来验证自定义的类型。其中一种情况如在request请求中基于各种请求返回各种序列化对象,而不是直接返回MoyaResponse。这种需求可以通过向TargetType中添加associatetype来完成。
protocol DecodableTargetType: Moya.TargetType {
associatedType ResultType: SomeJSONDecodableProtocolConformance
}
enum UserApi: DecodableTargetType {
case get(id: Int)
case update(id: Int, name: String)
...
var baseURL: URL { ... }
var path: String { switch self ... }
var method: Moya.Method { ... }
typealias ResultType = UserModel
}
因为associatedtype,所以MultiTarget不能被当做DecodableTargetType类型(ps:因为它MultiTarget源码实现没有实现这个扩展协议)。所以我们需要使用MultiMoyaProvider的变体。它不需要一个泛型参数(经过查看相关issue话题,这个作者考虑后的设计,推荐强类型)。因此,请求可以被调用并且任何遵循TargetType协议的实例对象都可以作为参数。使用MultiMoyaProvider允许你使用关联类型来编写及包装请求
例如,我们可以创建一个requestDecoded方法并返回ResultType而不是直接返回MoyaResponse。
extension MultiMoyaProvider {
func requestDecoded<T: DecodableTargetType>(_ target: T, completion: @escaping (_ result: Result<[T.ResultType], Moya.Error>) -> ()) -> Cancellable {
return request(target) { result in
switch result {
case .success(let response):
if let parsed = T.ResultType.parse(try! response.mapJSON()) {
completion(.success(parsed))
} else {
completion(.failure(.jsonMapping(response)))
}
case .failure(let error):
completion(.failure(error))
}
}
}
}
这个代码的优美之处在于,它的回调中的输入类型隐式的由传入的target类型决定
你可以传递任何DecodableTargetType来启动请求
let provider = MultiMoyaProvider()
provider.requestDecoded(UserApi.get(id: 1)) { result in
switch result {
case .success(let user):
// type of `user` is implicitly `UserModel`. Using any other type results
// in compile error
print(user.name)
}
}
当使用关联类型时,你将不得不为各种的target定义各种不同的类型。比如,我们有一另外一个target--SessionApi
struct SessionApi: DecodableTargetType {
typealias ResultType = SessionModel
}
它有不同的ResultType。但我们可以使用MultiMoyaProvider的同一个实例对象:
provider.requestDecoded(SessionApi.get) { result in
switch result {
case .success(let session):
// type of `user` is implicitly `SessionModel` here
}
}
总结 这小节的核心:
- 当TargetType的实现里面的API太多了,需要分割成多个独立的TargetType,而常规使用MoyaProvider来创建请求就会变得庞大了。所以MutiTarget乘时而生。
- MutiTarget的使用
- 在MutiTarget中如何使用关联类型。(关键是扩展MultiMoyaProvider,例如一个返回结果的模型序列化的实现)
ps: 没有找到MultiMoyaProvider,自己推断它就是MoyaProvider??
经过搜索Moya github issue 找到个 [WIP] MoyaProvider variant without generic parameter #910
对于实现为 class MultiMoyaProvider: MoyaProvider<MultiTarget> { }
网友评论