From d6a847bfccb96b9e325e922ed0dd34566b992237 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sun, 6 Feb 2022 10:24:07 -0500 Subject: [PATCH] Use background image preparation apis on iOS 15 Closes #128 --- Tusker/Caching/ImageCache.swift | 48 ++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/Tusker/Caching/ImageCache.swift b/Tusker/Caching/ImageCache.swift index 986800a4..248ae2fb 100644 --- a/Tusker/Caching/ImageCache.swift +++ b/Tusker/Caching/ImageCache.swift @@ -22,6 +22,7 @@ class ImageCache { #endif private let cache: ImageDataCache + private let desiredPixelSize: CGSize? private var groups = MultiThreadDictionary(name: "ImageCache request groups") @@ -30,28 +31,47 @@ class ImageCache { init(name: String, memoryExpiry: CacheExpiry, diskExpiry: CacheExpiry? = nil, desiredSize: CGSize? = nil) { // todo: might not always want to use UIScreen.main for this, e.g. Catalyst? let pixelSize = desiredSize?.applying(.init(scaleX: UIScreen.main.scale, y: UIScreen.main.scale)) + self.desiredPixelSize = pixelSize self.cache = ImageDataCache(name: name, memoryExpiry: memoryExpiry, diskExpiry: diskExpiry, storeOriginalDataInMemory: diskExpiry == nil, desiredPixelSize: pixelSize) } func get(_ url: URL, loadOriginal: Bool = false, completion: ((Data?, UIImage?) -> Void)?) -> Request? { let key = url.absoluteString - if !ImageCache.disableCaching, - let entry = try? cache.get(key, loadOriginal: loadOriginal) { - if let completion = completion { - backgroundQueue.async { - completion(entry.data, entry.image) + + let wrappedCompletion: ((Data?, UIImage?) -> Void)? + if let completion = completion { + wrappedCompletion = { (data, image) in + if #available(iOS 15.0, *) { + if !loadOriginal, + let size = self.desiredPixelSize { + image?.prepareThumbnail(of: size, completionHandler: { + completion(data, $0) + }) + } else { + image?.prepareForDisplay { + completion(data, $0) + } + } + } else { + self.backgroundQueue.async { + completion(data, image) + } } } + } else { + wrappedCompletion = nil + } + + if !ImageCache.disableCaching, + let entry = try? cache.get(key, loadOriginal: loadOriginal) { + wrappedCompletion?(entry.data, entry.image) return nil } else { if let group = groups[url] { - if let completion = completion { - return group.addCallback(completion) - } - return nil + return group.addCallback(wrappedCompletion) } else { let group = createGroup(url: url) - let request = group.addCallback(completion) + let request = group.addCallback(wrappedCompletion) group.run() return request } @@ -122,21 +142,15 @@ class ImageCache { task!.resume() } - private func updatePriority() { - task?.priority = max(1.0, URLSessionTask.defaultPriority + 0.1 * Float(requests.filter { !$0.cancelled }.count)) - } - func addCallback(_ completion: ((Data?, UIImage?) -> Void)?) -> Request { let request = Request(callback: completion) requests.append(request) - updatePriority() return request } func cancelWithoutCallback() { if let request = requests.first(where: { $0.callback == nil && !$0.cancelled }) { request.cancel() - updatePriority() } } @@ -145,8 +159,6 @@ class ImageCache { if remaining <= 0 { task?.cancel() complete(with: nil) - } else { - updatePriority() } }