Skip to content

Instantly share code, notes, and snippets.

@johnclayton
Created April 1, 2022 17:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johnclayton/47cf549425d1dfaa8e69e69dcf792a41 to your computer and use it in GitHub Desktop.
Save johnclayton/47cf549425d1dfaa8e69e69dcf792a41 to your computer and use it in GitHub Desktop.
Closure based image loader
import UIKit
import Combine
final class ImageLoader {
typealias LoadPublisher = AnyPublisher<UIImage, Error>
typealias Cache = NSCache<CacheKey, UIImage>
private let loadImage: (URL, Cache) -> LoadPublisher
private let cachedImage: (URL, Cache) -> UIImage?
init(
loadImage: @escaping (URL, Cache) -> LoadPublisher,
cachedImage: @escaping (URL, Cache) -> UIImage?
) {
self.loadImage = loadImage
self.cachedImage = cachedImage
}
}
extension ImageLoader {
final class CacheKey: NSObject {
let key: URL
init(_ key: URL) {
self.key = key
}
override func isEqual(_ object: Any?) -> Bool {
guard let object = object as? Self else { return false }
return object.key == key
}
override var hash: Int {
key.hashValue
}
}
}
// The live version can be accessed easily from the environment via .live
extension ImageLoader {
static var live: ImageLoader = {
let liveImageCache = Cache()
Self(
loadImage: { url, cache in
enum Error: Swift.Error {
case noData
case invalidImageData
}
// Fetch images for real here
// One can use a dispatch queue internally or just a lock
let image = UIImage()
cache.setObject(image, forKey: .init(url))
return Just(image)
.setFailureType(to: Swift.Error.self)
.eraseToAnyPublisher()
},
cachedImage: { url, cache in
cache.object(forKey: .init(url))
}
)
}()
}
// It's so easy to create a preview version...
#if DEBUG
extension ImageLoader {
static var preview: ImageLoader = {
let liveImageCache = Cache()
Self(
loadImage: { url, cache in
let image = UIImage()
cache.setObject(image, forKey: .init(url))
return Just(image)
.setFailureType(to: Error.self)
.eraseToAnyPublisher()
},
cachedImage: { url, cache in
cache.object(forKey: .init(url))
}
)
}()
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment