Async sequences let you work with values that come over time, like waiting for messages or data without stopping your program.
Async sequences (AsyncSequence) in Swift
struct MyAsyncSequence: AsyncSequence { typealias Element = Int struct AsyncIterator: AsyncIteratorProtocol { var current = 0 mutating func next() async -> Int? { guard current < 5 else { return nil } defer { current += 1 } return current } } func makeAsyncIterator() -> AsyncIterator { AsyncIterator() } }
An AsyncSequence must define an AsyncIterator that produces values asynchronously.
The next() method returns the next value or nil when done.
for await number in MyAsyncSequence() { print(number) }
let numbers = MyAsyncSequence() var iterator = numbers.makeAsyncIterator() Task { while let number = await iterator.next() { print(number) } }
This program counts down from 3 to 1, waiting half a second between each number, then prints "Blast off!".
import Foundation struct Countdown: AsyncSequence { typealias Element = Int struct AsyncIterator: AsyncIteratorProtocol { var count: Int mutating func next() async -> Int? { guard count > 0 else { return nil } try? await Task.sleep(nanoseconds: 500_000_000) // wait 0.5 seconds defer { count -= 1 } return count } } let start: Int func makeAsyncIterator() -> AsyncIterator { AsyncIterator(count: start) } } @main struct Main { static func main() async { let countdown = Countdown(start: 3) for await number in countdown { print("Countdown: \(number)") } print("Blast off!") } }
Use for await to loop over async sequences easily.
Async sequences help keep your app responsive by not blocking while waiting for data.
Remember to mark functions using async sequences with async and run them in async contexts.
Async sequences let you handle streams of values that come over time without blocking.
Define an AsyncIterator with a next() method that returns values asynchronously.
Use for await loops to process these values simply and clearly.
Practice
AsyncSequence in Swift?Solution
Step 1: Understand AsyncSequence purpose
AsyncSequence is designed to handle values that come asynchronously over time, like events or data streams.Step 2: Compare options with AsyncSequence use
Only To handle streams of values that arrive over time without blocking the program correctly describes handling streams without blocking, which is the key feature of AsyncSequence.Final Answer:
To handle streams of values that arrive over time without blocking the program -> Option CQuick Check:
AsyncSequence = handle async streams [OK]
- Confusing AsyncSequence with synchronous loops
- Thinking AsyncSequence is for static data
- Assuming it blocks program execution
AsyncSequence named numbers?Solution
Step 1: Recall AsyncSequence iteration syntax
AsyncSequence requires asynchronous iteration usingfor awaitto wait for values.Step 2: Check each option
for await number in numbers { print(number) } usesfor await, which is correct. for number in numbers { print(number) } is synchronous, C is invalid syntax for AsyncSequence, and D is not supported.Final Answer:
for await number in numbers { print(number) } -> Option AQuick Check:
AsyncSequence loops use for await [OK]
- Using regular for loop without await
- Trying to call next() synchronously
- Using forEach which is not async-compatible
struct Counter: AsyncSequence {
typealias Element = Int
struct AsyncIterator: AsyncIteratorProtocol {
var count = 1
mutating func next() async -> Int? {
guard count <= 3 else { return nil }
defer { count += 1 }
return count
}
}
func makeAsyncIterator() -> AsyncIterator {
AsyncIterator()
}
}
let counter = Counter()
Task {
for await number in counter {
print(number)
}
}Solution
Step 1: Analyze AsyncIterator next() method
The iterator returns count starting at 1, increments after returning, and stops after 3.Step 2: Trace iteration values
Values returned are 1, then 2, then 3, then nil to end the loop.Final Answer:
1 2 3 -> Option AQuick Check:
AsyncSequence yields 1,2,3 then ends [OK]
- Assuming count starts at 0
- Forgetting defer increments count after return
- Expecting 4 as output
struct SimpleAsync: AsyncSequence {
typealias Element = String
struct AsyncIterator: AsyncIteratorProtocol {
func next() async -> String? {
return "Hello"
}
}
func makeAsyncIterator() -> AsyncIterator {
AsyncIterator()
}
}Solution
Step 1: Understand AsyncIteratorProtocol requirements
The next() method often needs to update internal state, so it must be marked mutating in a struct.Step 2: Check the code's next() method
Here, next() is not mutating but returns a constant string repeatedly, which is incorrect for iteration.Final Answer:
next() should be mutating to update state -> Option BQuick Check:
next() mutating required in struct iterator [OK]
- Thinking AsyncIterator must be a class
- Making makeAsyncIterator async unnecessarily
- Believing String cannot be Element type
Solution
Step 1: Identify required sequence
Even numbers from 2 to 10 inclusive: 2, 4, 6, 8, 10 exactly.Step 2: Trace execution of each
A (< 10, defer +=2): 2,4,6,8 (stops at current=10). Misses 10.
B (*2 on odds): 2,4,6,8,10,12,... overshoots.
C (<=10, +=2 first): 2,4,6,8,10,12 extra.
D (if >10 nil, result first): 2,4,6,8,10 perfect.Final Answer:
if current > 10 { return nil }
let result = current
current += 2
return result -> Option DQuick Check:
Only D emits exactly 2,4,6,8,10 [OK]
- Incrementing before returning causing off-by-one errors
- Incorrect guard conditions excluding last value
- Multiplying inside next() causing wrong sequence
Ready to prove it?
Pass the test and this pattern moves unknown
