'Why does this swift async-await code fails with leaked continuation?
I am experimenting with Swift async-await and AsyncSequence protocol,
Here is the code:
struct AsyncNumbers<Element: Numeric>: AsyncSequence {
private let numbers: [Element]
init(_ numbers: [Element]) {
self.numbers = numbers
}
func makeAsyncIterator() -> AsyncNumberIterator {
return AsyncNumberIterator(numbers)
}
}
extension AsyncNumbers {
struct AsyncNumberIterator: AsyncIteratorProtocol {
private let numbers: [Element]
private var index = -1
init(_ numbers: [Element]) {
self.numbers = numbers
}
mutating func next() async -> AsyncNumbers<Element>.Element? {
index += 1
return await withCheckedContinuation { [self] continuation in
Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { timer in
guard index < numbers.count else {
continuation.resume(returning: nil)
timer.invalidate()
return
}
continuation.resume(returning: numbers[index])
}
}
}
}
}
func printNumbers() async {
let numbers = AsyncNumbers([5,78,3,45,99,100,23,4,7,8,9])
for await num in numbers {
print("Number:", num)
}
print("End")
}
Task {
await printNumbers()
}
This code fails before even the first number is printed to the console, with error SWIFT TASK CONTINUATION MISUSE: next() leaked its continuation!
,
I don't understand why I am getting this error here, the timer block is called only once after 2 seconds no duplicate calls to the continuation block are happening here,
Does anyone know what might the issue?
Thank you in advance :)
Solution 1:[1]
As several rightly commented, the problem is your use of Timer
and Concurrency
.
Timer.scheduledTimer
requires a runloop to work. In contrast to the main thread, secondary threads do not have a runloop until you explicitly create it.
Since you are calling this from a coroutine in the body of an await
function, your thread context is a secondary thread. This means that at the time of you calling Timer.scheduledTimer
you are not having a runloop, hence the timer callback will never be called and – depending on the context of the surrounding code – Swift rightly warns you that you are leaking the coroutine.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | DrMickeyLauer |