[회고] 신입 iOS 개발자가 되기까지 feat. 카카오 자세히보기

🍎 Apple/Swift

[Swift] URLSession Cahce Policy

inu 2022. 5. 18. 16:28
반응형

Network Caching

  • 네트워크 작업은 고비용의 작업입니다. 따라서 매번 동일한 데이터를 받아올 때마다 요청과 응답을 수행하게된다면 시간 및 리소스를 상당히 낭비하게 됩니다.
  • 그래서 필요한 것이 Caching입니다. Caching을 사용하면 불필요한 작업을 최대한 줄여서 시스템의 성능을 향상시킬 수 있습니다.
  • URL Loading System을 통해 이러한 Caching에 설정을 수행할 수 있습니다.
  • Cache Store 및 Cache Policy를 변경할 수 있습니다.
  • URL Loading System에서는 4가지 Cache Policy를 제공합니다.
    • useProtocolCachePolicy : protocol 특성에 따른 기본 캐시정책 (서버에서 전달한 Cache-Control Header를 그대로 따름)
    • reloadIgnoringLocalCacheData : local 캐시를 무시하고 항상 네트워크에 접속하도록 설정하는 정책
    • returnCacheDataDontLoad : 네트워크에 접속하지 않고 항상 local 캐시를 사용하도록 설정하는 정책
    • returnCacheDataElseLoad : local 캐시를 확인하고 캐시가 없는 경우에만 네트워크에 접속하도록 설정하는 정책
  • Cache를 저장하는 기간이 너무 길면 이미 관련 데이터가 업데이트되었음에도 사용자는 예전 데이터를 보게될 위험이 있습니다. 따라서 이를 적절히 관리하도록 하는 것이 중요합니다.
  • Cache 관련 설정은 Request 혹은 Session 단계에서 설정이 가능합니다.
  • 이렇게 저장되는 Cache에는 단순한 Data 뿐 아니라 서버 응답과 관련된 메타 데이터도 함께 저장됩니다. 저장 타입은 CachedURLResponse 입니다.

Request에서 설정하기

  • Request에서 Cache를 설정하는 방법을 알아봅시다.
    var request = URLRequest(url: url)
    request.cachePolicy = .returnCacheDataElseLoad
  • request에 cachePolicy를 지정하기만하면 됩니다.
  • 다만 이와 같이 returnCacheDataElseLoad 정책을 사용할 경우 캐시의 저장기간이 가장 중요합니다. 앞서 언급했듯이 이미 관련 데이터가 업데이트되었음에도 사용자는 예전 데이터를 보게될 위험이 있기 때문입니다.
  • Swift에서는 Cache를 삭제하는 다양한 메서드를 제공하지만, 제대로 동작하지 않는 경우가 더 많아 전체 캐시를 삭제하는 메서드를 제외하고는 사용하지 않는다고 합니다.
  • 따라서 Cache를 삭제하지 않고 Cache Policy를 임시로 바꾸는 방법으로 문제를 해결합니다.
    var lastDate: Data?
    ...
    if lastDate.timeIntervalSinceNow < -5 {
       request.cachePolicy = .reloadIgnoringLocalCacheData
       lastDate = Date()
    } else {
       request.cachePolicy = .returnCacheDataElseLoad
    }
  • 이런 방식입니다.
  • 마지막으로 접근한 시간과 현재시간을 비교해 캐시정책을 임시로 바꿔 접근하도록합니다.
    session.configuration.urlCache?.removeAllCachedResponses()
  • 참고로 전체 캐시를 삭제하는 방법은 위와 같습니다.

Session에서 설정하기

  • 다음으로 Session에서 설정하는 방법입니다.
      let config = URLSessionConfiguration.default

      config.requestCachePolicy = .returnCacheDataElseLoad

      let session = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main)
  • config에서 requestCachePolicy를 설정할 수 있습니다.
  • 다만 Request에서 Cache Policy를 설정했다면 그 설정이 더 우선적으로 적용됩니다.

Delegate를 사용하여 캐시에 추가적인 처리하기

  • URLSessionDataDelegate에는 cache가 처리되기 전에 호출되는 Delegate method가 존재합니다.
    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, willCacheResponse proposedResponse: CachedURLResponse, completionHandler: @escaping (CachedURLResponse?) -> Void) {
        completionHandler(proposedResponse)
    }
  • proposedResponse에는 현재 캐시에 저장되려는 데이터입니다.
  • 이를 completionHandler에 전달하면 캐시에 저장이 수행됩니다.
    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, willCacheResponse proposedResponse: CachedURLResponse, completionHandler: @escaping (CachedURLResponse?) -> Void) {
        guard let url = proposedResponse.response.url else {
            completionHandler(nil)
            return
        }

        if url.scheme == "https" {
            let response = CachedURLResponse(response: proposedResponse.response, data: proposedResponse.data, userInfo: proposedResponse.userInfo, storagePolicy: .allowedInMemoryOnly)
            completionHandler(response)
        } else {
            let response = CachedURLResponse(response: proposedResponse.response, data: proposedResponse.data, userInfo: proposedResponse.userInfo, storagePolicy: .notAllowed)
            completionHandler(response)
        }
    }
  • 이런 방식을 응용하면 위와 같은 처리가 가능해집니다.
  • url의 scheme이 https인 경우에만 메모리 캐싱을 허용하고 있습니다.
반응형