Philipp Otto Philipp Otto - 1 month ago 25
iOS Question

AlamofireImage Disk Cache not working

I want to use AlamofireImage to download images from an url and then cache it on the device disk space. I read several posts about this and found out that AlamofireImage supports this with the help of the ImageDownloader class. The most interesting information was given in this SO answer

So I tried to set a custom NSURLCache for the ImageDownloader so that it would cache the images directly to the disk. I did that by setting the memory capacity to 0. Then I use this custom ImageDownloader to download an image. The folder that I specified for the disk path is created on the disk but unfortunately it stays empty and the image is not cached in any way.

Can anybody tell me what I am doing wrong here? Thanks very much for reading!

func diskImageDownloader(diskSpaceMB: Int = 100) -> ImageDownloader {

let diskCapacity = diskSpaceMB * 1024 * 1024
let diskCache = NSURLCache(memoryCapacity: 0, diskCapacity: diskCapacity, diskPath: "alamofireimage_disk_cache")
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.URLCache = diskCache
let downloader = ImageDownloader(configuration: configuration)
UIImageView.af_sharedImageDownloader = downloader

return downloader
}

func getProfileImage(atURL url: String, onComplete: SRServiceResponse<UIImage> -> Void) {
guard let imageURL = NSURL(string: url) else
{
// TODO: Fail here
return
}

let request = NSURLRequest(URL: imageURL)

let imageDownloader = self.diskImageDownloader()

imageDownloader.downloadImage(URLRequest: request) { (response) in
switch response.result
{
case .Success(let image):
// Do something
case .Failure(let error):
// Do something
}
}
}

Answer

to reach your goal make your NSURLCache which you use as diskCache really custom to set your own expiration date for the stored images:

class DiskCache: NSURLCache {
    private let constContentType = "Content-Type"
    private let constSecondsToKeepOnDisk = 30*24*60*60 // 30 days

    override func storeCachedResponse(cachedResponse: NSCachedURLResponse, forRequest request: NSURLRequest) {
        var customCachedResponse = cachedResponse
        // Set custom Cache-Control for Image-Response
        if let response = cachedResponse.response as? NSHTTPURLResponse,
            let contentType = response.allHeaderFields[constContentType] as? String,
            var newHeaders = response.allHeaderFields as? [String: String] where contentType.containsString("image") {
            newHeaders[constContentType] = "public, max-age=\(constSecondsToKeepOnDisk)"
            if let url = response.URL, newResponse = NSHTTPURLResponse(URL: url, statusCode: response.statusCode, HTTPVersion: "HTTP/1.1", headerFields: newHeaders) {
                customCachedResponse = NSCachedURLResponse(response: newResponse, data: cachedResponse.data, userInfo: cachedResponse.userInfo, storagePolicy: cachedResponse.storagePolicy)
            }
        }
        super.storeCachedResponse(customCachedResponse, forRequest: request)
    }
}

Instead of creating a new ImageDownloader every time you could reuse the shared instance to call the downloadImage method: UIImageView.af_sharedImageDownloader.downloadImage(URLRequest: request)