so I'm reading the Modern Concurrency book from raywenderlich.com and I assume the book must be outdated or something, I'm trying to run the closure insde the AsyncStream but it doesn't seem to get there, I'm still pretty new to this Async/Await thing, but when adding some breakpoints I can see my code is not getting there. This is my code and a screenshot with some warnings showing. I am not really familiar with what the warnings mean, just trying to learn all this new stuff, I would truly appreciate some help and is there a way to fix it with Swift 6? Thanks in advance!
Reference to captured var 'countdown' in concurrently-executing code; this is an error in Swift 6
Mutation of captured var 'countdown' in concurrently-executing code; this is an error in Swift 6
func countdown(to message: String) async throws {
guard !message.isEmpty else { return }
var countdown = 3
let counter = AsyncStream<String> { continuation in
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
continuation.yield("\(countdown)...")
countdown -= 1
}
}
for await countDownMessage in counter {
try await say(countDownMessage)
}
}

Timer.scheduleTimerrequires that it be scheduled on a run loop. In practical terms, that means we would want to schedule it on the main thread’s run loop. So, you either callscheduleTimerfrom the main thread, or create aTimerand manuallyadd(_:forMode:)it toRunLoop.main. See the Scheduling Timers in Run Loops section of theTimerdocumentation.The easiest way would be to just isolate this function to the main actor. E.g.,
There a few other issues here, too:
I would suggest defining the
countdownvariable within theAsyncStream:The
AsyncStreamis never finished. You might want to finish it when it hits zero:There should be a
continuation.onTerminationclosure to handle cancelation of the asynchronous sequence.Going back to the original question (why this is not running), I personally would avoid the use of
Timerin conjunction with Swift concurrency at all. A GCD timer would be better, as it doesn’t require aRunLoop. Even better, I would adviseTask.sleep. Needless to say, that is designed to work with Swift concurrency, and also is cancelable.I personally would suggest something like: