Using async/await for ImageCache implementation
This commit is contained in:
parent
ebfd8b3efd
commit
29596180a1
|
@ -32,46 +32,38 @@ class ImageCache {
|
|||
}
|
||||
|
||||
func get(_ url: URL, loadOriginal: Bool = false, completion: ((Data?, UIImage?) -> Void)?) -> Request? {
|
||||
let key = url.absoluteString
|
||||
|
||||
let wrappedCompletion: ((Data?, UIImage?) -> Void)?
|
||||
if let completion = completion {
|
||||
wrappedCompletion = { (data, image) in
|
||||
if let image {
|
||||
if !loadOriginal,
|
||||
let size = self.desiredPixelSize {
|
||||
image.prepareThumbnail(of: size) {
|
||||
completion(data, $0)
|
||||
}
|
||||
} else {
|
||||
image.prepareForDisplay {
|
||||
completion(data, $0)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
completion(data, image)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
wrappedCompletion = nil
|
||||
}
|
||||
|
||||
if !ImageCache.disableCaching,
|
||||
let entry = try? cache.get(key, loadOriginal: loadOriginal) {
|
||||
wrappedCompletion?(entry.data, entry.image)
|
||||
let entry = try? cache.get(url.absoluteString, loadOriginal: loadOriginal) {
|
||||
completion?(entry.data, entry.image)
|
||||
return nil
|
||||
} else {
|
||||
let task = dataTask(url: url, completion: wrappedCompletion)
|
||||
task.resume()
|
||||
return task
|
||||
return Task.detached(priority: .userInitiated) {
|
||||
let result = await self.fetch(url: url)
|
||||
switch result {
|
||||
case .data(let data):
|
||||
completion?(data, nil)
|
||||
case .dataAndImage(let data, let image):
|
||||
completion?(data, image)
|
||||
case .none:
|
||||
completion?(nil, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func get(_ url: URL, loadOriginal: Bool = false) async -> (Data?, UIImage?) {
|
||||
// todo: this should integrate with the task cancellation mechanism somehow
|
||||
return await withCheckedContinuation { continuation in
|
||||
_ = get(url, loadOriginal: loadOriginal) { data, image in
|
||||
continuation.resume(returning: (data, image))
|
||||
if !ImageCache.disableCaching,
|
||||
let entry = try? cache.get(url.absoluteString, loadOriginal: loadOriginal) {
|
||||
return (entry.data, entry.image)
|
||||
} else {
|
||||
let result = await self.fetch(url: url)
|
||||
switch result {
|
||||
case .data(let data):
|
||||
return (data, nil)
|
||||
case .dataAndImage(let data, let image):
|
||||
return (data, image)
|
||||
case .none:
|
||||
return (nil, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -81,21 +73,28 @@ class ImageCache {
|
|||
guard !ImageCache.disableCaching else { return }
|
||||
|
||||
if !((try? cache.has(url.absoluteString)) ?? false) {
|
||||
let task = dataTask(url: url, completion: nil)
|
||||
task.resume()
|
||||
Task.detached(priority: .medium) {
|
||||
_ = await self.fetch(url: url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func dataTask(url: URL, completion: ((Data?, UIImage?) -> Void)?) -> URLSessionDataTask {
|
||||
return URLSession.shared.dataTask(with: url) { data, response, error in
|
||||
guard error == nil,
|
||||
let data else {
|
||||
return
|
||||
}
|
||||
let image = UIImage(data: data)
|
||||
try? self.cache.set(url.absoluteString, data: data, image: image)
|
||||
completion?(data, image)
|
||||
private func fetch(url: URL) async -> FetchResult {
|
||||
guard let (data, _) = try? await URLSession.shared.data(from: url) else {
|
||||
return .none
|
||||
}
|
||||
guard let image = UIImage(data: data) else {
|
||||
try? cache.set(url.absoluteString, data: data, image: nil)
|
||||
return .data(data)
|
||||
}
|
||||
let preparedImage: UIImage?
|
||||
if let desiredPixelSize {
|
||||
preparedImage = await image.byPreparingThumbnail(ofSize: desiredPixelSize)
|
||||
} else {
|
||||
preparedImage = await image.byPreparingForDisplay()
|
||||
}
|
||||
try? cache.set(url.absoluteString, data: data, image: preparedImage ?? image)
|
||||
return .dataAndImage(data, preparedImage ?? image)
|
||||
}
|
||||
|
||||
func getData(_ url: URL) -> Data? {
|
||||
|
@ -114,6 +113,12 @@ class ImageCache {
|
|||
return cache.disk?.getSizeInBytes()
|
||||
}
|
||||
|
||||
typealias Request = URLSessionDataTask
|
||||
typealias Request = Task<Void, Never>
|
||||
|
||||
enum FetchResult {
|
||||
case data(Data)
|
||||
case dataAndImage(Data, UIImage)
|
||||
case none
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue