Issue #133

Swift Concurrency is Gaining Broader Adoption

Cover for Weekly Issue 133

Photo by Tomas Sobek on Unsplash

It has been almost 5 years since Swift 5.5 introduced a new concurrency model aligned with modern programming paradigms. From 5.5 to the current 6.3, the Swift community has been actively advancing the evolution of concurrency APIs through small, iterative steps. However, this process hasn’t exactly been smooth sailing for developers, who had to grapple with a plethora of new keywords, complex isolation concepts, and some confusing “anti-patterns.”

As a newsletter editor, I’ve seen a massive amount of complaints and pleas for help over the past few years, but this sense of anxiety seems to have noticeably faded since the beginning of this year. In recent months, there have been more and more success stories shared within the community about migrating legacy projects to the new concurrency model. Although there are still a few scattered complaints, the prevailing attitude has shifted toward active embrace. Looking at the practical results, the new code—born from the growing pains of refactoring—has significantly reduced the cognitive load on developers when maintaining concurrency states.

Of course, behind this phenomenon, aside from developers becoming increasingly proficient with the new system, the maturity of the ecosystem also deserves a lot of credit. Over the past few years, both first-party and third-party frameworks and components have gradually completed their transition to the new concurrency implementations. This has greatly lowered the barrier to entry, allowing an increasing number of developers to immediately enjoy the convenience and data safety it brings.

There is also an interesting factor at play: thanks to the selfless sharing of many excellent content creators and open-source authors in the community, AI has accumulated a much richer corpus of Swift concurrency data over the past year or two. The new generation of large language models released in recent months clearly possesses a more accurate understanding of Swift’s concurrency rules, which has greatly accelerated developers’ mastery and application of the new concurrency.

Imperceptibly, the development of Swift’s new concurrency has entered a virtuous cycle. As can be seen from the new features in Swift 6.3, following the release of version 6.2, the evolution of Swift concurrency has largely entered a stable phase. Consequently, the community’s focus has shifted toward broader areas such as cross-platform and embedded development.

Perhaps the term “new concurrency model” in Swift can soon drop the “new” label and officially become part of the lifeblood of our daily development. Of course, it’s not entirely impossible that in another five to ten years, yet another “brand-new” concurrency model will arrive to amaze (or torture) us once again.

Recent Recommendations

The Flaky Test That Taught Me How Swift Concurrency Actually Works

Writing a test MockClock to support debounce behavior may not seem difficult for many Swift developers. But if you overlook differences in execution context — the executor — the result may be less deterministic than expected. Through the debugging process of a real-world case, Xiangyu reveals many details of modern Swift concurrency: nonisolated async functions hop away from the caller’s actor; Task.yield() only yields the current executor; and isolated parameters plus #isolation can let utility functions “run with the caller.” The value of this article is not in how to implement a test Clock, but in how clearly it shows the real relationship between tasks, actors, executors, and isolation in Swift Concurrency.

As Swift evolves, the behavior of nonisolated is no longer always equivalent to “necessarily hopping away from the current caller.” It can also be affected by the language mode and settings such as NonisolatedNonsendingByDefault. I ran into a similar issue, and solved it in the same way: with isolated + #isolation.


What’s that “structured” in Structured Concurrency?

Although Task has a handle and can be cancelled, making it look “more structured” than dispatch_async, its definition in Swift’s modern concurrency system is actually quite clear: Task is an unstructured top-level task. In this article, Max Seelemann explains what “structured” really means: the truly structured concurrency constructs are essentially async let and TaskGroup. What they share is an inescapable dependency relationship: the caller must wait for the subtasks to complete, and cancellation automatically propagates downward. Task, by contrast, is the opposite — it can be freely created and forgotten, with a lifecycle detached from the caller.

The article ends with a practical suggestion: use closures instead of Task whenever possible. Expressing a unit of work as () async -> Void is simpler, easier to test, and naturally inherits cancellation behavior from the calling context compared with passing around a Task object.


SwiftUI: Refreshable Task Cancellation

.refreshable accepts an async closure in which developers can fetch new data and update view state. But it has an easy-to-miss pitfall: if you modify the @State that drives the current view while the closure is running, the resulting redraw may cancel the refreshable task before it completes. In this article, Anton Gubarenko clearly explains this behavior: the lifecycle of .refreshable is tied to the view, and if a redraw is triggered during the refresh process, SwiftUI may terminate the task early — in other words, the task is cancelled by the very update it caused.

The author gives two possible fixes: either collect intermediate results in a local variable and update state once at the end, avoiding repeated redraws; or wrap the actual work in Task { }.value, allowing it to “detach” from the current refresh task and avoid being interrupted by the view lifecycle.

The issue faced by .refreshable also exists with .task. This is not a bug, but a concrete expression of SwiftUI’s structured concurrency model: async tasks are attached to the view lifecycle and are cancelled when that lifecycle ends. Without realizing this, it is easy to create a “self-cancellation” scenario between state updates and task execution.


Swift 6.3 experimentalCGen guide: SwiftPM natively supports C code generation

The experimentalCGen feature introduced in Swift 6.3 fills a long-standing gap in SwiftPM: C-family artifacts generated by Build Tool Plugins can finally participate directly in the compilation of C module targets, without relying on external scripts or precommitted generated files. This means the complete build graph can be closed within SwiftPM — local builds, CI, and Xcode can all use the same rules instead of each maintaining part of the build knowledge. In this article, Snow gives a detailed overview of the background, usage, and migration path for this feature.

experimentalCGen still has clear limitations. For example, each target can only have one generated module map, and headers referenced by that module map must be located in the same directory. As a result, it is better suited to code generation workflows with clear boundaries and stable outputs, rather than serving as a replacement for a full native build system.


How I migrated 300 screens to SwiftUI and what I learned

Migrating 300 screens to SwiftUI sounds like a complete transformation, but the strategy adopted by Artem Mirzabekian and his team was quite restrained: SwiftUI was responsible only for UI construction, while navigation remained in UIKit. This separation was not a compromise, but a deliberate choice — allowing the team to benefit from SwiftUI’s strengths in layout and component reuse while avoiding unnecessary risks around navigation, deep linking, and complex flows. The article records recurring issues during the migration: the team was used to imperative thinking and often wrote SwiftUI as “UIKit with different syntax”; side effects were placed inside body; onAppear was treated as viewDidLoad; nested ObservableObject structures led to unexpected state propagation problems. After continuous review and internal workshops, the team eventually settled on a clear architectural direction: MVVM + enum-driven state and interaction modeling + Use Cases for separating business logic.

Even outside migration projects, combining SwiftUI and UIKit is a realistic and effective choice. The two frameworks are not opposed to each other. Mixing them is not the hard part; the real challenge is writing code that fits each framework’s intended mental model.

Tools

Mini Swift: A Swift Compiler Written in Pure C

A fascinating project with a strong hacker spirit. Without using LLVM, Clang, or any official Apple toolchain, Ugur Toprakdeviren single-handedly wrote a lightweight Swift compiler in more than 70,000 lines of C. Starting from lexical analysis and the AST, he built the pipeline all the way to a backend that directly outputs WASM, bringing an astonishing sub-0.1 ms “instant compilation” experience to the web. In an era where pulling in hundreds of megabytes of dependencies is common, this zero-dependency act of “building the wheel by hand” feels almost romantically retro.

The project began with a simple goal: to build a SwiftUI browser preview that would not crash. The author also revealed that he is currently developing a layer called UIIR — a UI intermediate representation — with the eventual goal of mapping SwiftUI code into a platform-independent set of instructions that can render native-like results directly on the Web or even Android, fulfilling his original vision.

The compiler frontend’s core code — lexer, parser, and semantic analysis — is currently open source.

If combined with a terminal-based WASM runtime (such as Wasmtime), Mini Swift could significantly alleviate the current pain point of slow cold starts when writing terminal scripts in Swift, truly enhancing the Swift scripting experience. I am very much looking forward to seeing community explorations in this direction.


Yotei: A SwiftUI Calendar Component Library

Yotei is an iOS calendar component library by Mikalai Zmachynski. The project provides SwiftUI APIs while relying on UIKit to maintain scrolling performance in high-load scenarios such as schedule lists, pagination, and timelines. It includes components such as a date picker, day timeline, month grid, and schedule list, along with fairly detailed customization entry points.

Yotei demonstrates an increasingly common trade-off in complex SwiftUI components: SwiftUI handles composition, state binding, and extension points, while UIKit provides more mature and stable list and paging behavior.


Runtime Viewer

If you still remember RuntimeBrowser, then Runtime Viewer, developed by Mx-Iris, can be seen as a modern rewrite of that idea for today’s Apple platform context. It can browse not only Objective-C runtime information, but also Swift types, enum layouts, VTable offsets, and more, while offering a code-reading experience close to Xcode.

It is not merely a tool that “shows more interfaces.” Instead, it brings runtime inspection, cross-process communication, code injection, Bonjour device discovery, and even MCP integration into a single tool. For developers interested in reverse engineering, security research, learning system frameworks, or simply understanding the internal structure of a binary, it feels more like a runtime inspection workbench for modern Apple platforms.

Related Weekly

Subscribe to Fatbobman

Weekly Swift & SwiftUI highlights. Join developers.

Subscribe Now