Files
Moya/docs_CN/Providers.md
2018-08-15 14:53:20 +08:00

6.7 KiB
Raw Permalink Blame History

(供应者)Providers

当使用Moya时, 您通过MoyaProvider实例进行所有API请求,并把指定要调用哪个Endpoint的enum的值传递给它。在你设置了 Endpoint之后, 基本用法实际上配置完毕了:

let provider = MoyaProvider<MyService>()

在如此简单的设置之后您就可以直接使用了:

provider.request(.zen) { result in
    // `result` is either .success(response) or .failure(error)
}

到此完毕! request() 方法返回一个Cancellable, 它有一个你可以取消request的公共的方法。 更多关于Result类型的信息查看 Examples

记住, 把target和provider放在哪儿完全取决于您自己。 您可以查看 Artsy的实现 的例子.

但是别忘了持有它的一个引用 . 如果它被销毁了你将会在response上看到一个 -999 "canceled" 错误 。

高级用法

为了解释 MoyaProvider所有的配置选项我们将会按照下面的小节一个一个的来解析 。

(endpoint闭包)endpointClosure:

MoyaProvider 构造器的第一个(可选的)参数是一个 endpoints闭包, 它负责把您的enum值映射成一个Endpoint实例对象。 让我们看看它是什么样子的。

let endpointClosure = { (target: MyTarget) -> Endpoint in
    let url = URL(target: target).absoluteString
    return Endpoint(url: url, sampleResponseClosure: {.networkResponse(200, target.sampleData)}, method: target.method, task: target.task)
}
let provider = MoyaProvider(endpointClosure: endpointClosure)

注意在这个MoyaProvider的构造器中我们不再有指定泛型 ,因为Swift将会自动从endpointClosure的类型中推断出来。 非常灵巧!

您有可能已经注意到了URL(target:) 构造器, Moya 提供了一个便利扩展来从任意 TargetType中创建 URL。

这个endpointClosure就像您看到的这样简单. 它其实也是Moya的默认实现, 这个实现存储在 MoyaProvider.defaultEndpointMapping. 查看 Endpoints 文档来查看 为什么 您可能想自定义这个。

(请求闭包)requestClosure:

下一个初始化参数是requestClosure,它分解一个Endpoint 成一个实际的 URLRequest. 同样的, 查看 Endpoints 文档了解为什么及如何来做这个 。

(stub闭包)stubClosure:

下一个选择是来提供一个stubClosure。这个闭包返回 .never (默认的), .immediate 或者可以把stub请求延迟指定时间的.delayed(seconds)三个中的一个。 例如, .delayed(0.2) 可以把每个stub 请求延迟0.2s. 这个在单元测试中来模拟网络请求是非常有用的。

更棒的是如果您需要对请求进行区别性的stub,那么您可以使用自定义的闭包。

let provider = MoyaProvider<MyTarget>(stubClosure: { target: MyTarget -> Moya.StubBehavior in
    switch target {
        /* Return something different based on the target. */
    }
})

但通常情况下,您希望所有目标都有同样的stub行为。在 MoyaProvider中有三个静态方法您可以使用。

MoyaProvider.neverStub
MoyaProvider.immediatelyStub
MoyaProvider.delayedStub(seconds)

所以,在上面的示例上,如果您希望为所有的target立刻进行stub行为,下面的两种方式都可行 。

let provider = MoyaProvider<MyTarget>(stubClosure: { (_: MyTarget) -> Moya.StubBehavior in return .immediate })
let provider = MoyaProvider<MyTarget>(stubClosure: MoyaProvider.immediatelyStub)

(管理器)manager:

接下来就是manager参数. 默认您将会获得一个基本配置的自定义的Alamofire.Manager实例对象

public final class func defaultAlamofireManager() -> Manager {
    let configuration = URLSessionConfiguration.default
    configuration.httpAdditionalHeaders = Alamofire.Manager.defaultHTTPHeaders

    let manager = Alamofire.Manager(configuration: configuration)
    manager.startRequestsImmediately = false
    return manager
}

这儿只有一个需要注意的事情: 由于在AF中创建一个Alamofire.Request默认会立即触发请求,即使为单元测试进行 "stubbing" 请求也一样。 因此在Moya中, startRequestsImmediately 属性被默认设置成了 false 。

如果您喜欢自定义自己的 manager, 比如, 添加SSL pinning, 创建一个并且添加到manager, 所有请求将通过自定义配置的manager进行路由.

let policies: [String: ServerTrustPolicy] = [
    "example.com": .PinPublicKeys(
        publicKeys: ServerTrustPolicy.publicKeysInBundle(),
        validateCertificateChain: true,
        validateHost: true
    )
]

let manager = Manager(
    configuration: URLSessionConfiguration.default,
    serverTrustPolicyManager: ServerTrustPolicyManager(policies: policies)
)

let provider = MoyaProvider<MyTarget>(manager: manager)

插件:

最后, 您可能也提供一个plugins数组给provider。 这些插件会在请求被发送前及响应收到后被执行。 Moya已经提供了一些插件: 一个是 网络活动(NetworkActivityPlugin),一个是记录所有的 网络活动 (NetworkLoggerPlugin), 还有一个是 HTTP Authentication.

例如您可以通过传递 [NetworkLoggerPlugin()] 给 plugins参考来开启日志记录 。注意查看也可以配置的, 比如,已经存在的 NetworkActivityPlugin 需要一个 networkActivityClosure 参数. 可配置的插件实现类似这样的:

public final class NetworkActivityPlugin: PluginType {

    public typealias NetworkActivityClosure = (change: NetworkActivityChangeType) -> ()
    let networkActivityClosure: NetworkActivityClosure

    public init(networkActivityClosure: NetworkActivityClosure) {
        self.networkActivityClosure = networkActivityClosure
    }

    // MARK: Plugin

    /// Called by the provider as soon as the request is about to start
    public func willSend(request: RequestType, target: TargetType) {
        networkActivityClosure(change: .began)
    }

    /// Called by the provider as soon as a response arrives
    public func didReceive(data: Data?, statusCode: Int?, response: URLResponse?, error: ErrorType?, target: TargetType) {
        networkActivityClosure(change: .ended)
    }
}

networkActivityClosure 是一个当网络请求开始或结束时提供通知的闭包。 这个和 network activity indicator一起来用是非常有用的。 注意这个闭包的签名是 (change: NetworkActivityChangeType) -> (), 所以只有当请求是.began 或者.ended(您没有提供任何关于网络请求的细节) 时您才会被通知。