Last active
March 10, 2024 21:42
-
-
Save thomsmed/aaebf367c57913843e8ebf2cf1b4685a to your computer and use it in GitHub Desktop.
A concurrent and thread safe resource cache that spawns an unstructured Task to fetch a resource when the resource is first requested. All Tasks requesting the resource will wait on the completion of the spawned unstructured resource fetching Task.
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
// | |
// TaskSpawningResourceCache.swift | |
// | |
import Foundation | |
/// A concurrent and thread safe resource cache that spawns an unstructured Task to fetch a resource when the resource is first requested. | |
/// All Tasks requesting the resource will wait on the completion of the spawned unstructured resource fetching Task. | |
final actor TaskSpawningResourceCache { | |
private let urlSession: URLSession | |
private var cachedResource: Data? | |
private var resourceFetchingTask: Task<Data?, Never>? | |
init(urlSession: URLSession = .shared) { | |
self.urlSession = urlSession | |
} | |
// MARK: - Private | |
private func fetchResource() async -> Data? { | |
let url = URL(string: "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/132.png")! | |
let request = URLRequest(url: url) | |
do { | |
let (data, _) = try await urlSession.data(for: request) | |
return data | |
} catch { | |
// Ignoring proper Error handling for simplicity. | |
print("Failed to fetch resource:", error) | |
return nil | |
} | |
} | |
// MARK: - Public | |
var resource: Data? { | |
get async { | |
if let cachedResource { | |
return cachedResource | |
} | |
if let resourceFetchingTask { | |
return await resourceFetchingTask.value | |
} | |
let task = Task<Data?, Never> { [weak self] in | |
guard let self else { | |
return nil | |
} | |
return await self.fetchResource() | |
} | |
resourceFetchingTask = task | |
let resource = await task.value | |
cachedResource = resource | |
resourceFetchingTask = nil | |
return resource | |
} | |
} | |
var freshResource: Data? { | |
get async { | |
cachedResource = nil | |
return await resource | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment