Last active
November 22, 2023 21:56
-
-
Save hcrub/b1605943bc3ce76f5d938d8c84d365ff to your computer and use it in GitHub Desktop.
Swift Image Manager Singleton
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 | |
/// Data Manager error types. | |
/// | |
/// - noData: No valid data was received. | |
/// - parsingFailure: The data parsing failed. | |
/// - endpointFailure: The endpoint failed. | |
/// - invalidInput: The input was invalid. | |
/// - anyError: Generic wrapped error. | |
enum DataError: Error { | |
case noData | |
case parsingFailure | |
case endpointFailure | |
case invalidInput | |
case anyError(Any) | |
} | |
/// ImageDataManager | |
/// | |
/// Class for fetching and caching remote images. | |
final class ImageDataManager: NSObject { | |
// MARK: Shared | |
/// Shared image cache instance. | |
static var shared = ImageDataManager() | |
private override init() {} | |
// MARK: Internal | |
/// The internal image cache management. | |
private var imageCache = [String:UIImage]() | |
/// The internal task cache management. | |
private var taskCache = [String:URLSessionDataTask]() | |
} | |
// MARK: - DataManager | |
extension ImageDataManager { | |
/// Fetches the image with the URL. | |
/// | |
/// - Parameters: | |
/// - URL: The URL of the image. | |
/// - completion: The completion handler. | |
func fetchRequest(with input: URL, completion: @escaping (UIImage?, DataError?) -> ()) { | |
let key = input.absoluteString | |
// Check if we've already cached the image. | |
if let cachedImage = imageCache[key] { | |
completion(cachedImage, nil) | |
return | |
} | |
// Fetch the image. | |
let task = URLSession.shared.dataTask(with: input) { [unowned self] (data, response, error) in | |
defer { | |
self.taskCache[key] = nil | |
} | |
// Generic data error. | |
if let dataError = error { | |
completion(nil, DataError.anyError(dataError)); | |
return | |
} | |
// Empty data error. | |
guard let data = data else { | |
completion(nil, DataError.noData) | |
return | |
} | |
// Image conversion error. | |
guard let image = UIImage(data: data) else { | |
completion(nil, DataError.parsingFailure) | |
return | |
} | |
completion(image, nil) | |
self.imageCache[key] = image | |
} | |
// Run and store the task. | |
taskCache[key] = task | |
task.resume() | |
} | |
/// Cancels the image request with the URL. | |
/// | |
/// - Parameter URL: The URL of the fetched image. | |
func cancelRequest(with URL: URL) { | |
let key = URL.absoluteString | |
guard let task = taskCache[key] else { return } | |
task.cancel() | |
taskCache[key] = nil | |
} | |
} | |
// MARK: - UIImageView Support | |
extension UIImageView { | |
/// Asynchronously fetches and sets the image with the URL. | |
/// | |
/// - Parameter URL: The URL of the remote image. | |
func setImage(with URL: URL) { | |
ImageDataManager.shared.fetchRequest(with: URL) { [weak self] (image, error) in | |
guard error == nil else { return } | |
DispatchQueue.main.async { | |
self?.image = image | |
} | |
} | |
} | |
/// Cancels the image request with the image URL. | |
/// | |
/// - Parameter URL: The URL of the remote image. | |
func cancelImage(for URL: URL) { | |
ImageDataManager.shared.cancelRequest(with: URL) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment