skip to Main Content

I want to cache the response of API. When the internet is available it should fetch data from the server and should update locally cached data every time and when the internet is not available it should show cached data. Is it possible with Alamofire or URLSession? or do I need to use a database and I should manually handle this?

2

Answers


  1. Chosen as BEST ANSWER

    With Alamofire, It can be achieved as below,

    import Alamofire
    
    class NetworkLogger: EventMonitor {
        
        let queue = DispatchQueue(label: "com.ketan.almofire.networklogger")
        
        func requestDidFinish(_ request: Request) {
            print(request.description)
        }
        
        func request<Value>(
            _ request: DataRequest,
            didParseResponse response: DataResponse<Value, AFError>
        ) {
            guard let data = response.data else {
                return
            }
            if let json = try? JSONSerialization
                .jsonObject(with: data, options: .mutableContainers) {
                print(json)
            }
        }
    }
    
    class APIClient {
        
        private var manager = Session()
        
        init() {
            configureSession()
        }
        
        private func manageCachePolicy() {
            
            if NetworkReachabilityManager()?.isReachable ?? false {
                manager.sessionConfiguration.requestCachePolicy = .reloadIgnoringLocalCacheData
            } else {
                manager.sessionConfiguration.requestCachePolicy = .returnCacheDataElseLoad
            }
        }
        
        private func configureSession() {
            
            let configuration = URLSessionConfiguration.default
            configuration.requestCachePolicy = .returnCacheDataElseLoad
            if NetworkReachabilityManager()?.isReachable ?? false {
                configuration.requestCachePolicy = .reloadIgnoringLocalCacheData
            }
            
            manager = Session(configuration: configuration, eventMonitors: [NetworkLogger()])
            
            ///When we don't want network logs
            // manager = Session(configuration: configuration)
            
        }
        
        // MARK: - Request
        func requestData(_ convertible: URLConvertible,
                         method: HTTPMethod = .get,
                         parameters: Parameters? = nil,
                         encoding: ParameterEncoding = URLEncoding.default,
                         headers: HTTPHeaders? = nil,
                         completion: @escaping (Result<Data, ErrorResult>) -> Void) {
            
            manageCachePolicy()
            manager.request(convertible,
                            method: method,
                            parameters: parameters,
                            encoding: encoding,
                            headers: headers).validate().responseData
            { (response) in
                switch response.result {
                case .success(let data):
                    completion(.success(data))
                case .failure(let error):
                    completion(.failure(.network(string: error.localizedDescription)))
                }
            }
            
        }
    }
    

  2. What if you did something like this using URLRequest

    var urlRequest = URLRequest(url: url)
    // Configure your URLRequest as you wish with headers etc
    
    // Load from the cache
    urlRequest.cachePolicy = .returnCacheDataDontLoad
    
    // Load from the source
    if networkStatus == available {
        urlRequest.cachePolicy = .reloadIgnoringLocalCacheData
    }
    
    let task = URLSession.shared.dataTask(with: urlRequest) { [weak self] data, response, error in
    
       // You will get data from the source when internet is available
       // You will get data from your cache when internet isn't available
       if let data = data {
          // Reload your UI with new or cached data
       }
    
       // There is some error in your request or server
       // Or the internet isn't available and the cache is empty
       if let error = error {
          // Update your UI to show an error accordingly
       }
    
    }
    
    task.resume()
    

    Update based on OPs comment

    I’m opening the application first time and the internet is there and
    data is loaded from the server. now I’m closing my internet and
    opening the app but data will not be displayed because it didn’t store
    data in the cache when the internet was there because of
    reloadIgnoringLocalCacheData this policy. this policy doesn’t store
    data in cache.

    Setting the cachePolicy to reloadIgnoringLocalCacheData does not mean don’t store any data in cache, it means ignore anything stored in cache and get data from the source.

    Using the default shared singleton of URLSession makes use of a default cache as per the docs

    From the docs

    The shared session uses the shared URLCache, HTTPCookieStorage, and
    URLCredentialStorage objects, uses a shared custom networking protocol
    list (configured with registerClass(🙂 and unregisterClass(:)), and
    is based on a default configuration.

    Give this a try, I tried based on the use case you mentioned above and it does what you want it to do.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search