It’s been a few years since I’ve heavily been in the Swift world. A lot has changed from the days of MVC-heavy architecture, UIKit and good old Interface Builder, and the occasional foray into newer, more modern patterns like MVVM and FRP with RxSwift. While I’ve enjoyed spending time with React and better understanding the wide world of JavaScript, I’ve been transitioning back to native iOS and Swift recently. In the process, one of the biggest standout themes is structured concurrency.
This post is a little playground for myself to try and better understand the evolution of concurrency and design patterns around data flow in Swift. Starting with a brief exploration into the background, historically there are a number of patterns for dealing with data, including:
Delegation
Publisher-subscriber
Callbacks
FRP with third-party frameworks like RxSwift
Grand Central Dispatch
Issues with completionHandlers:
guard let {}, else return all the things!
No way to enforce that closures are always invoked, leading to bugs
Extra noise when working with closures
Now there are ways to improve asynchronous code, including:
Result type to enforce conformity
Futures
Better but still not great
Now this is certainly workable, and if you’ve been working in Swift, and really in any software development position over the last 5 years you’ve surely used many of the above concepts, but is there no better way? There is! Introducing structured concurrency as a first class citizen in Swift! Enter async/await.
Allows for async to safely unblock thread
Allows for try-throw pattern to eliminate a lot of boilerplate with error handling
Results in fewer bugs relating to completion handlers
Other thoughts and callouts
What is an AsyncSequence? Just like a normal Sequence, except that it vends its elements asynchronously. It allows for await in for loops.
To be continued…