11import UIKit
22
3- struct ImageRequestOptions {
4- /// Resize the thumbnail to the given size. By default, `nil`.
5- ///
6- /// - warning: The size is in pixels.
7- var size : CGSize ?
8-
9- /// If enabled, uses ``MemoryCache`` for caching decompressed images.
10- var isMemoryCacheEnabled = true
11-
12- /// If enabled, uses `URLSession` preconfigured with a custom `URLCache`
13- /// with a relatively high disk capacity. By default, `true`.
14- var isDiskCacheEnabled = true
15- }
16-
173/// The system that downloads and caches images, and prepares them for display.
184actor ImageDownloader {
195 static let shared = ImageDownloader ( )
@@ -38,48 +24,44 @@ actor ImageDownloader {
3824 self . cache = cache
3925 }
4026
41- // MARK: - Images (URL)
42-
43- /// Downloads image for the given `URL`.
44- func image( from url: URL , options: ImageRequestOptions = . init( ) ) async throws -> UIImage {
45- var request = URLRequest ( url: url)
46- request. addValue ( " image/* " , forHTTPHeaderField: " Accept " )
47- return try await image ( from: request, options: options)
27+ func image( from url: URL , host: MediaHost ? = nil , options: ImageRequestOptions = . init( ) ) async throws -> UIImage {
28+ try await image ( for: ImageRequest ( url: url, host: host, options: options) )
4829 }
4930
50- /// Downloads image for the given `URLRequest`.
51- func image ( from request : URLRequest , options: ImageRequestOptions = . init ( ) ) async throws -> UIImage {
52- let key = makeKey ( for: request. url, size: options. size)
31+ func image( for request : ImageRequest ) async throws -> UIImage {
32+ let options = request . options
33+ let key = makeKey ( for: request. source . url, size: options. size)
5334 if options. isMemoryCacheEnabled, let image = cache [ key] {
5435 return image
5536 }
56- let data = try await data ( for: request, options : options )
37+ let data = try await data ( for: request)
5738 let image = try await ImageDecoder . makeImage ( from: data, size: options. size)
5839 if options. isMemoryCacheEnabled {
5940 cache [ key] = image
6041 }
6142 return image
6243 }
6344
64- // MARK: - Images (Blog)
65-
66- /// Returns image for the given URL authenticated for the given host.
67- func image( from imageURL: URL , host: MediaHost , options: ImageRequestOptions = . init( ) ) async throws -> UIImage {
68- let request = try await authenticatedRequest ( for: imageURL, host: host)
69- return try await image ( from: request, options: options)
70- }
71-
72- /// Returns data for the given URL authenticated for the given host.
73- func data( from imageURL: URL , host: MediaHost , options: ImageRequestOptions = . init( ) ) async throws -> Data {
74- let request = try await authenticatedRequest ( for: imageURL, host: host)
75- return try await data ( for: request, options: options)
45+ func data( for request: ImageRequest ) async throws -> Data {
46+ let urlRequest = try await makeURLRequest ( for: request)
47+ return try await _data ( for: urlRequest, options: request. options)
7648 }
7749
78- private func authenticatedRequest( for imageURL: URL , host: MediaHost ) async throws -> URLRequest {
79- var request = try await MediaRequestAuthenticator ( )
80- . authenticatedRequest ( for: imageURL, host: host)
81- request. setValue ( " image/* " , forHTTPHeaderField: " Accept " )
82- return request
50+ private func makeURLRequest( for request: ImageRequest ) async throws -> URLRequest {
51+ switch request. source {
52+ case . url( let url, let host) :
53+ var request : URLRequest
54+ if let host {
55+ request = try await MediaRequestAuthenticator ( )
56+ . authenticatedRequest ( for: url, host: host)
57+ } else {
58+ request = URLRequest ( url: url)
59+ }
60+ request. addValue ( " image/* " , forHTTPHeaderField: " Accept " )
61+ return request
62+ case . urlRequest( let urlRequest) :
63+ return urlRequest
64+ }
8365 }
8466
8567 // MARK: - Caching
@@ -115,8 +97,8 @@ actor ImageDownloader {
11597
11698 // MARK: - Networking
11799
118- private func data ( for request: URLRequest , options: ImageRequestOptions ) async throws -> Data {
119- let requestKey = request. urlRequest ? . url? . absoluteString ?? " "
100+ private func _data ( for request: URLRequest , options: ImageRequestOptions ) async throws -> Data {
101+ let requestKey = request. url? . absoluteString ?? " "
120102 let task = tasks [ requestKey] ?? ImageDataTask ( key: requestKey, Task {
121103 try await self . _data ( for: request, options: options, key: requestKey)
122104 } )
@@ -198,7 +180,7 @@ extension ImageDownloader {
198180 nonisolated func downloadImage( for request: URLRequest , completion: @escaping ( UIImage ? , Error ? ) -> Void ) -> ImageDownloaderTask {
199181 let task = Task {
200182 do {
201- let image = try await self . image ( from : request , options : . init ( ) )
183+ let image = try await self . image ( for : ImageRequest ( urlRequest : request ) )
202184 completion ( image, nil )
203185 } catch {
204186 completion ( nil , error)
0 commit comments