Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cache Handling with Moya

We have implemented Moya, RxSwift And Alamofire as pods in our project.

Does anyone know how you gain control of the cache policies per url request using this tech?

I have read through quite a few of the issues on Moya's GitHub page but still can't find anything. Also tried using actual json response stored as files for the sampleData like so:

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

}

Thanks in advance for any pro tips :)

like image 732
AMAN77 Avatar asked Nov 27 '22 08:11

AMAN77


2 Answers

As to my understanding, the "cleanest" way to solve this, is to use a custom Moya Plugin. Here's an implementation:

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
    }
}

To actually use this plugin, there are two required steps left:

  1. The plugin should be added to your Moya provider like this:

    let moyaProvider = MoyaProvider<YourMoyaTarget>(plugins: [CachePolicyPlugin()])
    
  2. YourMoyaTargetshould conform to CachePolicyGettable and thereby define the cache policy for each target:

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

Note: This approach uses a protocol to associate cache policies with target types; one could also realise this via a closure being passed to the plugin. Such closure would then decide which cache policy to use depending on the target type passed as an input parameter to the closure.

like image 96
fredpi Avatar answered Dec 20 '22 23:12

fredpi


Based on @fredpi answer, I slightly improved caching plugin for Moya. Below is my version:

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
        }
    }
}

In order to clear the cache, you need to have an access to urlRequest object/objects. How to retrieve an urlRequest for Moya route you can find in the following topic.

To clear the cache you can use following code:

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) }
    }
}
like image 21
Stanislau Baranouski Avatar answered Dec 21 '22 01:12

Stanislau Baranouski