Skip to content

Instantly share code, notes, and snippets.

@amosavian
Last active April 12, 2024 13:56
Show Gist options
  • Save amosavian/a05044e57c290b5e064f4f7acfc3b506 to your computer and use it in GitHub Desktop.
Save amosavian/a05044e57c290b5e064f4f7acfc3b506 to your computer and use it in GitHub Desktop.
extension UIImageView {
/// Loads image from web asynchronosly and caches it, in case you have to load url
/// again, it will be loaded from cache if available
func load(url: URL, placeholder: UIImage?, cache: URLCache? = nil) {
let cache = cache ?? URLCache.shared
let request = URLRequest(url: url)
if let data = cache.cachedResponse(for: request)?.data, let image = UIImage(data: data) {
self.image = image
} else {
self.image = placeholder
URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in
if let data = data, let response = response, ((response as? HTTPURLResponse)?.statusCode ?? 500) < 300, let image = UIImage(data: data) {
let cachedData = CachedURLResponse(response: response, data: data)
cache.storeCachedResponse(cachedData, for: request)
self.image = image
}
}).resume()
}
}
}
@237-series
Copy link

Thanks

@thomasaw
Copy link

thomasaw commented Jun 9, 2020

In the last call to self.image = image you need to call it within a DispatchQueue.main.async { } block.

@aybekckaya
Copy link

image has not been set from main thread. However it should be set from main thread to prevent crashes.

    func load(url: URL, placeholder: UIImage?, cache: URLCache? = nil) {
        let cache = cache ?? URLCache.shared
        let request = URLRequest(url: url)
        if let data = cache.cachedResponse(for: request)?.data, let image = UIImage(data: data) {
            DispatchQueue.main.async {
                self.image = image
            }
        } else {
            self.image = placeholder
            URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in
                if let data = data, let response = response, ((response as? HTTPURLResponse)?.statusCode ?? 500) < 300, let image = UIImage(data: data) {
                    let cachedData = CachedURLResponse(response: response, data: data)
                    cache.storeCachedResponse(cachedData, for: request)
                    DispatchQueue.main.async {
                        self.image = image
                    }

                }
            }).resume()
        }
    }

@fethica
Copy link

fethica commented Nov 2, 2022

With more cleanup:

extension UIImageView {
    
    func load(url: URL, placeholder: UIImage?, cache: URLCache? = nil) {
        let cache = cache ?? URLCache.shared
        let request = URLRequest(url: url)
        
        if let data = cache.cachedResponse(for: request)?.data, let image = UIImage(data: data) {
            DispatchQueue.main.async {
                self.image = image
            }
        } else {
            self.image = placeholder
            
            URLSession.shared.dataTask(with: request) { [weak self] (data, response, error) in
                guard let data = data, let httpResponse = response as? HTTPURLResponse, 200...299 ~= httpResponse.statusCode, let image = UIImage(data: data) else { return }
                
                let cachedData = CachedURLResponse(response: httpResponse, data: data)
                cache.storeCachedResponse(cachedData, for: request)
                DispatchQueue.main.async {
                    self?.image = image
                }
            }.resume()
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment