I have a scenario where the user can try to refresh the app from multiple places, but I just want to refresh one time per request.
Just wanted to know if something like this could work, every time there is a second refresh or third request the app will wait for the current request that is running.
class Test {
private var currentTask: Task<Int, Never>?
@MainActor
func refresh() async -> Result<Int, Never> {
if let currentTask {
return await currentTask.result
}
let task = Task {
// Long operation
return 1
}
currentTask = task
let result = await task.result
currentTask = nil
return result
}
}
Yes this approach would work. I am using something very similar in my app.
actor Service {
private var task: Task<Void, Error>?
func fetchData() async throws {
if let task {
return try await task.value
}
let task = Task {
try await actualFetchData()
}
self.task = task
defer {
self.task = nil
}
return try await task.value
}
private func actualFetchData() async throws {
// Fetching data from the server/database
}
}
What you are basically doing is exposing a wrapper method that makes sure to perform the fetch request only if another one is not in progress. Your implementation should definitely work.
This functionality could be extended to support fetching discrete data for particular object, to which you would refer with its unique identifier.
actor Service {
private var tasks = [UUID: Task<Void, Error>]()
func fetchData(for uuid: UUID) async throws {
if let task = tasks[uuid] {
return try await task.value
}
let task = Task {
try await actualFetchData(for: uuid)
}
tasks[uuid] = task
defer {
tasks[uuid] = nil
}
return try await task.value
}
private func actualFetchData(for uuid: UUID) async throws {
// Fetching data from the server/database
}
}