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 = "https://upload.wikimedia.org/wikipedia/commons/e/e0/Large_Scaled_Forest_Lizard.jpg"
    let landscapeURLString = "https://images.pexels.com/photos/414171/pexels-photo-414171.jpeg"        

    override func viewDidLoad() 
        super.viewDidLoad()
        view.addSubview(imageView)
        view.addSubview(downloadLizzardbutton)
        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 
                print(error)
                return
            
            guard let httpResponse = response as? HTTPURLResponse,
                (200...299).contains(httpResponse.statusCode) else 
                    print("response NOT 2xx: (response)")
                    return
            

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

                DispatchQueue.main.async 
                    self?.imageView.image = image
                
            
        
        task.resume()
            
}


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

EDIT:

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

Leaked Aquaman Movie Suggests iTunes 4K Stream Cracked for First Time

satoshi

New iPhones Access Location Info When Settings are Disabled Due to Ultra Wideband, Toggle Coming in Future Update

satoshi

The Best Downloads of 2018: Our Favorite Software

satoshi

Trump Suggests Tariffs Could Be Placed on iPhones and Laptops Imported From China

satoshi

Ignore Your iPhone’s ‘Service’ Warning for Battery Replacements

satoshi

Another US court says police cannot force suspects to turn over their passwords

satoshi