docs_CN/Examples/MultiTarget.md
Provider中使用而采用 MultiTarget .当你有很多endpoints你可能以一个非常长的provider和在上百个case里多次切换而告终。你当然可以把这些逻辑分割到多个target中,但是你同时不得不使用多个provider。这会让你的app逻辑变复杂,并且如果你希望为它们配置相同的插件/闭包,你需要花费额外的功夫来管理它们。为了解决这个麻烦,我们可以使用内置的MultiTarget枚举类型,它是相当的易用。
首先, 我们需要定义一个使 multiple 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`
}
到此配置结束! 在您的app中采用它是相当的简单 而且如果您有很多想分割的
endpoints - 这是一个相当完美的解决方法. 如果你想看到这个API的作用, 查看我们的
Demo 项目, 它里面有两个
target: 一个是 Demo, 它使用的Moya的基础版; 另一个是DemoMultiTarget,它使用MultiTarget的修改版本 。
关联类型使用Moya能让您在调用网络请求时静态地验证参数。您可能想扩展Moya的 TargetType 并验证您的自定义类型。一种用例就是让请求方法返回基于请求的不同来序列化模型,而不是使用默认的MoyaResponse来返回。这可以通过在TargetType中添加 associatedtype来解决
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.
但是, 我们可以使用 MultiMoyaProvider 变体. 它不需要泛型参数. 所以, 任何遵循TargetType的实例对象都可以调用这个请求. 使用 MultiMoyaProvider 允许你编写可以使用associatedtype的请求包装器.
比如, 我们可以创建一个返回ResultType的 requestDecoded方法 来替换 MoyaResponse
extension MultiMoyaProvider {
func requestDecoded<T: DecodableTargetType>(_ target: T, completion: @escaping (_ result: Result<[T.ResultType], Moya.Error>) -> ()) -> Cancellable {
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))
}
}
}
}
其美妙之处在于,回调中的输入类型是由已传入的目标隐式地确定的.
您可以传入任何 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)
}
}
当使用 associatedtype, 您将需要为不同的类型定义不同的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
}
}