'Alamofire: How to conditionally change cache policy based on network status?

The end result I would like to achieve is to use cached data when the network is unavailable and load data from the server when the network is available.

The closest thing I've found is this thread, but I am still having trouble getting it to work using Alamofire. How to cache response in iOS and show only when internet is not available?

I have two classes, one to check the network status and another that configures an Alamofire url session. Detecting the network status seems to be working, but it's not changing the session configuration. What am I doing wrong? Thanks!

NetworkReachability.shared.startNetworkMonitoring() is run when the app loads in didFinishLaunchingWithOptions.

class NetworkReachability {
    static let shared = NetworkReachability()
    let reachabilityManager = NetworkReachabilityManager(host: "www.google.com")

    func startNetworkMonitoring() {
        reachabilityManager?.startListening(onUpdatePerforming: { status in
            switch status {
            case .notReachable:
                ApiManager.configuration.requestCachePolicy = .returnCacheDataDontLoad
            case .reachable(.cellular):
                ApiManager.configuration.requestCachePolicy = .reloadIgnoringCacheData
            case .reachable(.ethernetOrWiFi):
                ApiManager.configuration.requestCachePolicy = .reloadIgnoringCacheData
            case .unknown:
              print("Unknown network state")
            }
        })
    }
}

A custom api manager to configure the cache.

class ApiManager {
    static let shared = ApiManager()
    static let configuration = URLSessionConfiguration.af.default
    
    public let sessionManager: Alamofire.Session = {
        let responseCacher = ResponseCacher(behavior: .modify { _, response in
          let userInfo = ["date": Date()]
          return CachedURLResponse(
            response: response.response,
            data: response.data,
            userInfo: userInfo,
            storagePolicy: .allowed)
        })

        return Session(
            configuration: configuration,
            cachedResponseHandler: responseCacher)
    }()
}


Solution 1:[1]

I'm writing my APIClient here which I've written using Alamofire.

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

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Ketan Parmar