// // ImageCache.swift // Tusker // // Created by Shadowfacts on 8/21/18. // Copyright © 2018 Shadowfacts. All rights reserved. // import UIKit import Cache class ImageCache { static let avatars = ImageCache(name: "Avatars") let storage: Storage var requests = [URL: Request]() init(name: String, diskExpiry: Expiry = .seconds(60 * 60 * 24), memoryExpiry: Expiry = .seconds(60 * 60)) { self.storage = try! Storage( diskConfig: DiskConfig(name: name, expiry: diskExpiry), memoryConfig: MemoryConfig(expiry: memoryExpiry), transformer: TransformerFactory.forImage()) } func get(_ url: URL, completion: ((UIImage?) -> Void)?) { let key = url.absoluteString if (try? storage.existsObject(forKey: key)) ?? false, let image = try? storage.object(forKey: key) { completion?(image) } else { if let completion = completion, let request = requests[url] { request.callbacks.append(completion) } else { let request = Request(url: url, completion: completion) requests[url] = request request.run { (image) in try? self.storage.setObject(image, forKey: key) } } } } func cancel(_ url: URL) { requests[url]?.cancel() } class Request { let url: URL var task: URLSessionDataTask? var callbacks: [(UIImage?) -> Void] init(url: URL, completion: ((UIImage?) -> Void)?) { if let completion = completion { self.callbacks = [completion] } else { self.callbacks = [] } self.url = url } func run(cache: @escaping (UIImage) -> Void) { task = URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in guard error == nil, let data = data, let image = UIImage(data: data) else { self.complete(with: nil) return } cache(image) self.complete(with: image) }) task!.resume() } func cancel() { task?.cancel() complete(with: nil) } func complete(with image: UIImage?) { callbacks.forEach { $0(image) } } } }