Modern Swift Concurrency Patterns

Swift's concurrency model has evolved significantly. Beyond basic async/await, there's a whole ecosystem of patterns for handling streams, bridging legacy code, and ensuring thread safety.
Follow along with the code: iOS-Practice on GitHub
New here? Read the setup guide to get started.
What We'll Cover
This series dives into advanced concurrency patterns that often come up in interviews and production code:
AsyncSequence & AsyncStream
- Consuming async sequences with
for await - Building custom streams for any data source
- Bridging delegate-based APIs to modern Swift
Continuations
- Converting callback APIs to async/await
- The critical "resume exactly once" rule
Combine Operators
- Combining publishers:
combineLatest,merge,zip - Transforming streams:
flatMap,switchToLatest - Schedulers and threading
Thread Safety
- The
Sendableprotocol @MainActorpatterns for UI code- Preparing for Swift 6 strict concurrency
Why This Matters
These aren't edge cases. Real iOS apps need to:
- Stream location updates
- Handle real-time data from websockets
- Bridge old delegate APIs to modern code
- Ensure UI updates happen on the main thread
Understanding these patterns separates junior from senior developers.
The ConcurrencyWorkshop Project
All exercises live in the ConcurrencyWorkshop Xcode project. Each view demonstrates a specific pattern with interactive examples.
ConcurrencyWorkshop/
├── Exercises/
│ ├── AsyncSequences/
│ ├── Continuations/
│ ├── CombineOperators/
│ ├── Sendable/
│ └── MainActor/
Prerequisites
You should be comfortable with:
- Basic async/await syntax
- Swift actors
- Combine fundamentals (publishers, subscribers)
If you need a refresher, check out the earlier posts in this series on task cancellation and actor reentrancy.
Let's start with AsyncSequence—the foundation for streaming data in Swift.