5

我们在项目中将 Moya、RxSwift 和 Alamofire 实现为 pod。

有谁知道您如何使用此技术控制每个 url 请求的缓存策略?

我已经阅读了 Moya 的 GitHub 页面上的很多问题,但仍然找不到任何东西。还尝试使用存储为 sampleData 文件的实际 json 响应,如下所示:

var sampleData: Data {
    guard let path = Bundle.main.path(forResource: "SampleAggregate", ofType: "txt") else {
        return "sampleData".utf8Encoded
    }
    let sample = try? String(contentsOfFile: path, encoding: String.Encoding.utf8)
    return sample!.utf8Encoded

}

提前感谢任何专业提示:)

4

4 回答 4

25

据我了解,解决此问题的“最干净”的方法是使用自定义 Moya 插件。这是一个实现:

protocol CachePolicyGettable {
    var cachePolicy: URLRequest.CachePolicy { get }
}  

final class CachePolicyPlugin: PluginType {
    public func prepare(_ request: URLRequest, target: TargetType) -> URLRequest {
        if let cachePolicyGettable = target as? CachePolicyGettable {
            var mutableRequest = request
            mutableRequest.cachePolicy = cachePolicyGettable.cachePolicy
            return mutableRequest
        }

        return request
    }
}

要实际使用此插件,还需要两个必需的步骤:

  1. 该插件应该像这样添加到您的 Moya 提供程序中:

    let moyaProvider = MoyaProvider<YourMoyaTarget>(plugins: [CachePolicyPlugin()])
    
  2. YourMoyaTarget应该符合CachePolicyGettable并因此定义每个目标的缓存策略:

    extension YourMoyaTarget: CachePolicyGettable {
        var cachePolicy: URLRequest.CachePolicy {
            switch self {
            case .sampleTarget, .someOtherSampleTarget:
                return .reloadIgnoringLocalCacheData
    
            default:
                return .useProtocolCachePolicy
            }
        }
    }
    

注意:此方法使用协议将缓存策略与目标类型相关联;也可以通过传递给插件的闭包来实现这一点。然后,此类闭包将根据作为输入参数传递给闭包的目标类型来决定使用哪个缓存策略。

于 2018-06-06T19:42:12.000 回答
3

基于@fredpi 的回答,我稍微改进了 Moya 的缓存插件。下面是我的版本:

import Foundation
import Moya

protocol CachePolicyGettable {
    var cachePolicy: URLRequest.CachePolicy { get }
}

final class NetworkDataCachingPlugin: PluginType {

    init (configuration: URLSessionConfiguration, inMemoryCapacity: Int, diskCapacity: Int, diskPath: String?) {
        configuration.urlCache = URLCache(memoryCapacity: inMemoryCapacity, diskCapacity: diskCapacity, diskPath: diskPath)
    }

    func prepare(_ request: URLRequest, target: TargetType) -> URLRequest {
        if let cacheableTarget = target as? CachePolicyGettable {
            var mutableRequest = request
            mutableRequest.cachePolicy = cacheableTarget.cachePolicy
            return mutableRequest
        }
        return request
    }
}

extension NetworkApiService: CachePolicyGettable {
    var cachePolicy: URLRequest.CachePolicy {
        switch self {
        case .getUserProfile:
            return .returnCacheDataElseLoad
        default:
            return .useProtocolCachePolicy
        }
    }
}

为了清除缓存,您需要访问 urlRequest 对象/对象。如何检索 Moya 路由的 urlRequest,您可以在以下主题中找到。

要清除缓存,您可以使用以下代码:

public func clearCache(urlRequests: [URLRequest] = []) {
    let provider = ... // your Moya provider
    guard let urlCache = provider.manager.session.configuration.urlCache else { return }
    if urlRequests.isEmpty {
        urlCache.removeAllCachedResponses()
    } else {
        urlRequests.forEach { urlCache.removeCachedResponse(for: $0) }
    }
}
于 2018-11-12T10:39:17.540 回答
2

子类化MoyaProvider和组合requestClosure

它应该看起来像:

final class MyProvider<Target: TargetType>: MoyaProvider<Target> {

    public init(
        endpointClosure: @escaping EndpointClosure = MoyaProvider.defaultEndpointMapping,
        requestClosure: @escaping RequestClosure = MoyaProvider.defaultRequestMapping,
        stubClosure: @escaping StubClosure = MoyaProvider.neverStub,
        manager: Manager = MoyaProvider<Target>.defaultAlamofireManager(),
        plugins: [PluginType] = [],
        trackInflights: Bool = false
    ) {
        super.init(
            endpointClosure: endpointClosure,
            requestClosure: { endpoint, closure in
                var request = try! endpoint.urlRequest() //Feel free to embed proper error handling
                if request.url == URL(string: "http://google.com")! {
                    request.cachePolicy = .returnCacheDataDontLoad
                } else {
                    request.cachePolicy = .reloadIgnoringLocalAndRemoteCacheData
                }
                closure(.success(request))
            },
            stubClosure: stubClosure,
            manager: manager,
            plugins: plugins,
            trackInflights: trackInflights
        )
    }

}
于 2018-01-30T20:35:28.933 回答
0

如果您还想禁用存储的 cookie

request.httpShouldHandleCookies = false
于 2020-03-31T13:17:30.447 回答