如何在Swift中使用URLSession缓存图像

时间:2016-11-29 18:57:32

标签: swift3

我想增强下面的代码来缓存图片,只有在以前没有缓存它们时才下载它们。我似乎无法找到如何使用URLSession对象执行此操作的任何好例子。

extension UIImageView {
    func loadImageWithURL(_ url: URL) -> URLSessionDownloadTask {
        let session = URLSession.shared

        let downloadTask = session.downloadTask(with: url, completionHandler: { [weak self] url, response, error in

            if error == nil, let url = url,
                let data = try? Data(contentsOf: url), let image = UIImage(data: data) {

                    DispatchQueue.main.async {
                        if let strongSelf = self {
                            strongSelf.image = image
                        }
                    }
            }
        })
        downloadTask.resume()
        return downloadTask
    }
}

4 个答案:

答案 0 :(得分:8)

更新了Swift 4

import requests
from lxml import html
import urllib2
from bs4 import BeautifulSoup
import unicodecsv as csv
import os
import sys
import io
import time
import datetime
import pandas as pd
import MySQLdb
import mechanize
import cookielib

url = 'URL THE WEBSITE'
values = {
          'user': 'XXX',
          'password': 'YYY',
          'recaptcha-token': '03AOPBWq-Ltv5Op-YqU9WsKmE0qtNxr3w-gWwdLMxT4P1ri4j-P1IntWIGT6qRKcouZZr2hmuMPq7HPUL3NUV49gYSIfpnfunppH4tP9EjJO70tUpTaoRO1TkiPvDo8G6fmXaceEu6wMQINpG1-n_Xrp4CllvxcADrLhfmfEMTDmj7TLP-oLLBjFFT3MeMQdcQTndlQ4Kdv9gSTEgQPEl1ljaj1-wVg3zZ9msebL8aLH0Q4yC76AMhsOt4SXpwbliUbcvElWzxvV_uCSXs0jfenPbYYd9vxuy23aOL2kEcISpxsWn_rirDqd66JasBeqtMwTB7XCx_-_hlZlNGluqb4ARXThB7BDq7saKyPRW_TWG2L146qQKl6i9j59bvTE8qdzVMbqhkCboBSP3zTCj-pHkaG2gCrOlRTAVq2IxDNzIP8x0M4hLa8Ho'}

session = requests.Session()

r = session.post(url, data=values)

params = {'Category': 6, 'deltreeid': 6, 'do': 'Delete Tree'}
url = 'URL THE WEBSITE WHERE I WANT FIND THE RELEVANT INFORMATIONS'

result = session.get(url, data=params)

soup = BeautifulSoup(result.text, "lxml")
print soup

<强>用法:

import UIKit

let imageCache = NSCache<AnyObject, AnyObject>()

class ImageLoader: UIImageView {

    var imageURL: URL?

    let activityIndicator = UIActivityIndicatorView()

    func loadImageWithUrl(_ url: URL) {

        // setup activityIndicator...
        activityIndicator.color = .darkGray

        addSubview(activityIndicator)
        activityIndicator.translatesAutoresizingMaskIntoConstraints = false
        activityIndicator.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
        activityIndicator.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true

        imageURL = url

        image = nil
        activityIndicator.startAnimating()

        // retrieves image if already available in cache
        if let imageFromCache = imageCache.object(forKey: url as AnyObject) as? UIImage {

            self.image = imageFromCache
            activityIndicator.stopAnimating()
            return
        }

        // image does not available in cache.. so retrieving it from url...
        URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in

            if error != nil {
                print(error as Any)
                DispatchQueue.main.async(execute: {
                    self.activityIndicator.stopAnimating()
                })
                return
            }

            DispatchQueue.main.async(execute: {

                if let unwrappedData = data, let imageToCache = UIImage(data: unwrappedData) {

                    if self.imageURL == url {
                        self.image = imageToCache
                    }

                    imageCache.setObject(imageToCache, forKey: url as AnyObject)
                }
                self.activityIndicator.stopAnimating()
            })
        }).resume()
    }
}

答案 1 :(得分:4)

一个可能的解决方案是利用NSCache来处理缓存。基本上你要做的就是检查你是否已经在本地加载了图像,而不是每次在实际发出请求之前进行加载。

这是我的一个实现,但它是一个子类而不是扩展:

class CustomImageView: UIImageView {

    // MARK: - Constants

    let imageCache = NSCache<NSString, AnyObject>()

    // MARK: - Properties

    var imageURLString: String?

    func downloadImageFrom(urlString: String, imageMode: UIViewContentMode) {
        guard let url = URL(string: urlString) else { return }
        downloadImageFrom(url: url, imageMode: imageMode)
    }

    func downloadImageFrom(url: URL, imageMode: UIViewContentMode) {
        contentMode = imageMode
        if let cachedImage = imageCache.object(forKey: url.absoluteString as NSString) as? UIImage {
            self.image = cachedImage
        } else {
            URLSession.shared.dataTask(with: url) { data, response, error in
                guard let data = data, error == nil else { return }
                DispatchQueue.main.async {
                    let imageToCache = UIImage(data: data)
                    self.imageCache.setObject(imageToCache!, forKey: url.absoluteString as NSString)
                    self.image = imageToCache
                }
            }.resume()
        }
    }
}

此外,这是一个有用的资源: https://www.hackingwithswift.com/example-code/system/how-to-cache-data-using-nscache

答案 2 :(得分:0)

let imageCache = NSCache<AnyObject, AnyObject>()
extension UIImageView {

    func loadImageFromUrl(urlString: String)  {
        if let imageFromCache = imageCache.object(forKey: urlString as AnyObject) as? UIImage{
            self.image = imageFromCache
            return
        }

        Alamofire.request(urlString, method: .get).response { (responseData) in
            if let data = responseData.data {
               DispatchQueue.main.async {
                if let imageToCache = UIImage(data: data){
                    imageCache.setObject(imageToCache, forKey: urlString as AnyObject)
                    self.image = imageToCache
                }
            }
        }
    }

 }
}

答案 3 :(得分:0)

URLSession DataTask 默认会自动缓存图片,客户端不需要做任何事情,只要服务器端的缓存设置正常即可。图片是静态资源,短时间内不会改变,因此服务器通常会将“Cache-Control”设置为“public, max-age:xxxxx”。 URLSession 默认缓存策略将在内存和磁盘中缓存图像。但是,它不会缓存大于为 URLCache 分配的磁盘大小的 5% 的图像,也不会在后台线程中进行缓存。