forked from shadowfacts/Tusker
parent
9b33059089
commit
d6a847bfcc
|
@ -22,6 +22,7 @@ class ImageCache {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private let cache: ImageDataCache
|
private let cache: ImageDataCache
|
||||||
|
private let desiredPixelSize: CGSize?
|
||||||
|
|
||||||
private var groups = MultiThreadDictionary<URL, RequestGroup>(name: "ImageCache request groups")
|
private var groups = MultiThreadDictionary<URL, RequestGroup>(name: "ImageCache request groups")
|
||||||
|
|
||||||
|
@ -30,28 +31,47 @@ class ImageCache {
|
||||||
init(name: String, memoryExpiry: CacheExpiry, diskExpiry: CacheExpiry? = nil, desiredSize: CGSize? = nil) {
|
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?
|
// 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))
|
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)
|
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? {
|
func get(_ url: URL, loadOriginal: Bool = false, completion: ((Data?, UIImage?) -> Void)?) -> Request? {
|
||||||
let key = url.absoluteString
|
let key = url.absoluteString
|
||||||
|
|
||||||
|
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,
|
if !ImageCache.disableCaching,
|
||||||
let entry = try? cache.get(key, loadOriginal: loadOriginal) {
|
let entry = try? cache.get(key, loadOriginal: loadOriginal) {
|
||||||
if let completion = completion {
|
wrappedCompletion?(entry.data, entry.image)
|
||||||
backgroundQueue.async {
|
|
||||||
completion(entry.data, entry.image)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
if let group = groups[url] {
|
if let group = groups[url] {
|
||||||
if let completion = completion {
|
return group.addCallback(wrappedCompletion)
|
||||||
return group.addCallback(completion)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
} else {
|
} else {
|
||||||
let group = createGroup(url: url)
|
let group = createGroup(url: url)
|
||||||
let request = group.addCallback(completion)
|
let request = group.addCallback(wrappedCompletion)
|
||||||
group.run()
|
group.run()
|
||||||
return request
|
return request
|
||||||
}
|
}
|
||||||
|
@ -122,21 +142,15 @@ class ImageCache {
|
||||||
task!.resume()
|
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 {
|
func addCallback(_ completion: ((Data?, UIImage?) -> Void)?) -> Request {
|
||||||
let request = Request(callback: completion)
|
let request = Request(callback: completion)
|
||||||
requests.append(request)
|
requests.append(request)
|
||||||
updatePriority()
|
|
||||||
return request
|
return request
|
||||||
}
|
}
|
||||||
|
|
||||||
func cancelWithoutCallback() {
|
func cancelWithoutCallback() {
|
||||||
if let request = requests.first(where: { $0.callback == nil && !$0.cancelled }) {
|
if let request = requests.first(where: { $0.callback == nil && !$0.cancelled }) {
|
||||||
request.cancel()
|
request.cancel()
|
||||||
updatePriority()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,8 +159,6 @@ class ImageCache {
|
||||||
if remaining <= 0 {
|
if remaining <= 0 {
|
||||||
task?.cancel()
|
task?.cancel()
|
||||||
complete(with: nil)
|
complete(with: nil)
|
||||||
} else {
|
|
||||||
updatePriority()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue