Satoshi Nakamoto Blog
Image default
caching HTTP ios nsurlcache nsurlsession

ios – URLresponse is not retrieved after storing in cache using storeCachedResponse

I’m trying to inject data/response from URLRequest into another URLRequest in my cache.

This is just a sample code. It’s ready to be dumped into a project.

What I’m trying to do is use the response + data retrieved from my landscapeURLString network request…store into my session’s cache for my lizardURLString request.

import UIKit

class ViewController: UIViewController {

    lazy var defaultSession : URLSession = 
        let urlCache = URLCache(memoryCapacity: 500 * 1024 * 1024, diskCapacity: 500 * 1024 * 1024, diskPath: "something")
        let configuration = URLSessionConfiguration.default
        configuration.urlCache = urlCache
        let session = URLSession(configuration: configuration)

        return session
    lazy var downloadLizzardbutton : UIButton = 
        let btn = UIButton()
        btn.translatesAutoresizingMaskIntoConstraints = false
        btn.setTitle("download lizard image OFFLINE", for: .normal)
        btn.backgroundColor = .blue
        btn.addTarget(self, action: #selector(downloadLizardAction), for: .touchUpInside)
        return btn

    let imageView : UIImageView = 
        let imageView = UIImageView()
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.contentMode = .scaleAspectFill
        return imageView

    // I make sure my internet is set to OFF so that it forces this to be read from cache...
    @objc func downloadLizardAction() 
        downloadImage(from: lizardURLString, from: defaultSession)
    let lizardURLString = ""
    let landscapeURLString = ""        

    override func viewDidLoad() 
        imageView.pinToAllEdges(of: view)

        downloadImage(from: landscapeURLString, from: defaultSession)
    private func downloadImage(from urlString: String, from session : URLSession)
        guard let url = URL(string: urlString) else
            fatalError("bad String we got!")

        let urlRequest = URLRequest(url: url, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 15)
        print("url.hashValue: (urlRequest.hashValue)")

        let task = session.dataTask(with: urlRequest)  [weak self] (data, response, error) in

            guard error == nil else 
            guard let httpResponse = response as? HTTPURLResponse,
                (200...299).contains(httpResponse.statusCode) else 
                    print("response NOT 2xx: (response)")

            for header in httpResponse.allHeaderFields
                if let key = header.key as? String, key == "Cache-Control"
                    print("found Cache-Control: (httpResponse.allHeaderFields["Cache-Control"])")

            if let data = data,
                let image = UIImage(data: data)
                let lizardURL = URL(string: self!.lizardURLString)
                let lizardURLRequest = URLRequest(url: lizardURL!)

                let landscapeCachedURLPResponse : CachedURLResponse = CachedURLResponse(response: response!, data: data, userInfo:nil, storagePolicy: .allowed)
                print("before storing into cache: (String(describing: session.configuration.urlCache?.cachedResponse(for: lizardURLRequest)))")

                session.configuration.urlCache?.storeCachedResponse(landscapeCachedURLPResponse, for: lizardURLRequest)    

                print("after storing into cache: (String(describing: session.configuration.urlCache?.cachedResponse(for: lizardURLRequest)))")
                print("lizardRequest.hashValue: (lizardURLRequest.hashValue)")

                    self?.imageView.image = image

extension UIView

    func pinToAllEdges(of view: UIView)
        let leading = leadingAnchor.constraint(equalTo: view.leadingAnchor)
        let top = topAnchor.constraint(equalTo: view.topAnchor)
        let trailing = trailingAnchor.constraint(equalTo: view.trailingAnchor)
        let bottom = bottomAnchor.constraint(equalTo: view.bottomAnchor)

        NSLayoutConstraint.activate([leading, top, trailing, bottom])

Things I’ve already validated:

  • My landscapeURLString has a cache-control header with a max-age of 31536000
  • If it’s a fresh install, then before storing into the cache, my cachedResponse for lizardURLString is nil. But after storing, it’s no longer nil. As a result I conclude that I’m successfully storing something into the cache!
  • I also suspect the URLCache considers the URLRequest as the key. So I printed the hashValue of my lizardURLString. It’s same as the key I’ve stored. Combining that with the point above, I concluded that exact key exists in cache!
  • I can also see that when I store it in my cache, my currentMemoryUsage increases.

How I’m testing and what I’m seeing:

  1. I just download the landscape image.
  2. Turn off my internet
  3. Click the button to download the lizard image.

Obviously it’s offline. I expect it to use from the cache but it doesn’t. All I get is a time out!

I also tried changing the cachePolicy to returnCacheDataElseLoad, but that didn’t help either


I also tried doing what David said and do:

let landscapeHTTPResponse : HTTPURLResponse = HTTPURLResponse(url: self!.lizardURL, statusCode: 200, httpVersion: "HTTP/1.1", headerFields: (httpResponse.allHeaderFields as! [String : String]))!
let landscapedCachedURLPResponse : CachedURLResponse = CachedURLResponse(response: landscapeHTTPResponse, data: data, userInfo:nil, storagePolicy: .allowed)

and the stored landscapedCachedURLPResponse into the cache. That didn’t work either. It times out as well — it doesn’t every look into the cache.

Source link

Related posts

ios – Xcode 10, could not decode input file using specific encoding


Try These Mobile ‘Lemmings’ Games Instead of Sony’s Crappy Port


iPad Pro (2018) Bending Issue


ios – AES128 encryption in swift


The best text messaging apps for Android and iOS


Even Microsoft Edge thinks the Daily Mail website is an untrustworthy source of news