AsyncSequence: A Sequence That Awaits Its Next Element

AsyncSequence is like a regular Swift Sequence, but you await its next element. It lets you process values that arrive over time, like network data, without blocking. The footgun: iteration suspends, so run it in a Task for true concurrency.
Why it exists
Before Swift concurrency, processing asynchronous streams of data required complex patterns like Combine publishers or nested completion handlers. AsyncSequence was created to provide a structured, linear way to handle these events using the natural for await in loop syntax, making asynchronous code read like synchronous code.
The mental model
An AsyncSequence is like a regular Swift Sequence (e.g., an Array), but you await its next element. Imagine a conveyor belt where items appear at unpredictable intervals. A for await in loop is like a worker who waits for an item to arrive, processes it, and then waits for the next one, without holding up the entire factory.
How it works
An AsyncSequence provides an AsyncIterator. The for await in loop calls the iterator's next() method, which is marked async. This method can suspend execution until a value is available. When a value is produced, next() returns it. When the sequence is finished, next() returns nil, and the loop terminates. This allows the thread to perform other work while waiting.
When to use it
Use AsyncSequence for any series of values produced over time. It's ideal for reading a large file line-by-line (URL.lines), receiving data chunks from a network request (URLSession.bytes), or observing system notifications (NotificationCenter.notifications(named:)). It dramatically simplifies code that would otherwise rely on delegates or callbacks.
When not to use it
Avoid AsyncSequence for collections that are already fully loaded in memory. For a simple Array of data, a standard for in loop is more direct and performant. Using AsyncSequence for synchronous data adds unnecessary concurrency overhead without any benefit.
One canonical example
To read a text file line by line without loading the entire file into memory, URL.lines provides an AsyncSequence. You can iterate through it with: for await line in someURL.lines { print(line) }. This loop suspends while waiting for the next line to be read from disk, processes it, and then repeats, keeping memory usage low and the app responsive.
Interview question
For which scenario would using an AsyncSequence be least appropriate?
- a.Handling system-wide events as they are published over time.
- b.Processing elements of an array that is fully available in memory.Correct
- c.Receiving a continuous stream of data from a network connection.
- d.Iterating through lines of a large file without loading it all at once.
Why? this is the answer
AsyncSequence is designed for processing values that arrive over time, suspending execution until the next value is available. For collections already fully loaded in memory, a standard for-in loop is more direct and performant, as AsyncSequence would introduce unnecessary overhead.
Just read this? Test yourself on what you have been reading.
Read the original → developer.apple.com
- #swift
- #concurrency
- #ios
- #async/await
Put your scrolling time to good use
Learn one idea, try a quiz and save useful cards for revision. Tezvyn makes it easy to learn and stay current in your tech field, a few minutes at a time.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on swift — each one lists the topics its interview covers.
See open roles