Hi everyone,
I am playing around with Swift's concurrency and as an exercise, I wanted to make some kind of file downloader that could concurrently download multiple files.
I came up with a (surprisingly) working solution but I am unsure if this is a good solution or if there is any issue with what I've done.
Each download task is represented by the following (simplified) struct:
struct FileTask {
let url: URL
// ...
}
I then have the following functions that, given an array of tasks and an allowed number of concurrent downloads, will chunk the array and download the files using an async task group:
func download(tasks: [FileTask], maxConcurrent: Int = 0) async throws {
guard !tasks.isEmpty else {
return
}
let chunks: [[FileTask]]
if maxConcurrent == 0 {
chunks = [tasks]
} else {
chunks = stride(from: 0, to: tasks.count, by: maxConcurrent).map { index in
let upperLimit = min(index + maxConcurrent, tasks.count)
return Array(
tasks[index..<upperLimit]
)
}
}
for chunk in chunks {
await withThrowingTaskGroup(of: Void.self) { group in
for task in chunk {
group.addTask {
// function download(task: FileTask) -> async throws
// This function handles the network call and writes the file to disk
try await download(task: task)
}
}
}
}
}
I am very unsure about the for chunk in chunks
with an await
inside, is this an anti-pattern? Is there any limitation or caveat I should know about using this solution?