Skip to content

Instantly share code, notes, and snippets.

@kean
Created December 27, 2023 14:44
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kean/9fb9813ede243eeae9601d90207f884b to your computer and use it in GitHub Desktop.
Save kean/9fb9813ede243eeae9601d90207f884b to your computer and use it in GitHub Desktop.
actor SomeManager {
private var tasks: [String: DataTask] = [:]
private func data(for request: URLRequest) async throws -> Data {
let requestKey = request.urlRequest?.url?.absoluteString ?? ""
let task = tasks[requestKey] ?? DataTask(task: Task {
try await self._data(for: request, key: requestKey)
})
let subscriptionID = UUID()
task.subscriptions.insert(subscriptionID)
tasks[requestKey] = task
return try await withTaskCancellationHandler {
try await task.task.value
} onCancel: {
Task {
await self.unsubscribe(subscriptionID, key: requestKey)
}
}
}
private func unsubscribe(_ subscriptionID: UUID, key: String) {
guard let task = tasks[key],
task.subscriptions.remove(subscriptionID) != nil,
task.subscriptions.isEmpty else {
return
}
task.task.cancel()
tasks[key] = nil
}
private func _data(for request: URLRequest, key: String) async throws -> Data {
defer { tasks[key] = nil }
let (data, response) = try await session.data(for: request)
try validate(response: response)
return data
}
private final class DataTask {
var subscriptions = Set<UUID>()
var isCancelled = false
var task: Task<Data, Error>
init(subscriptions: Set<UUID> = Set<UUID>(), task: Task<Data, Error>) {
self.subscriptions = subscriptions
self.isCancelled = isCancelled
self.task = task
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment