Created
April 1, 2022 17:01
-
-
Save johnclayton/47cf549425d1dfaa8e69e69dcf792a41 to your computer and use it in GitHub Desktop.
Closure based image loader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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