As Swift 6 gradually gains adoption, this problem becomes increasingly prominent: developers want to benefit from the concurrency safety guarantees provided by the Swift compiler, while struggling with how to make their code meet compilation requirements. This article will demonstrate the clever use of
MainActor.assumeIsolatedin specific scenarios through an implementation case withNSTextAttachmentViewProvider.[…]
We seem to be caught in a dilemma: we need to construct
UIHostingControllerinMainActor, yet we cannot assign the constructed view (UIView) toself.viewwithinMainActor.[…]
Looking at
MainActor.assumeIsolated’s signature, we can see that this API provides a `Ma…
As Swift 6 gradually gains adoption, this problem becomes increasingly prominent: developers want to benefit from the concurrency safety guarantees provided by the Swift compiler, while struggling with how to make their code meet compilation requirements. This article will demonstrate the clever use of
MainActor.assumeIsolatedin specific scenarios through an implementation case withNSTextAttachmentViewProvider.[…]
We seem to be caught in a dilemma: we need to construct
UIHostingControllerinMainActor, yet we cannot assign the constructed view (UIView) toself.viewwithinMainActor.[…]
Looking at
MainActor.assumeIsolated’s signature, we can see that this API provides aMainActorcontext for its trailing closure. This means we can “synchronously” run code that can only execute in aMainActorcontext within a non-MainActorsynchronous context, without creating an async environment, and return aSendableresult.[…]
I still hope we can move past this somewhat “chaotic” transition period soon. Perhaps in a few years, when numerous official and third-party frameworks have completed their Swift 6 migration, we’ll finally enjoy a more relaxed safe concurrent programming experience.
I consistently find the
@preconcurrencyattribute to be confusing. But, I’m tired of that. Let’s just, once and for all, get a better handle how to use this thing.[…]
It has three distinct uses. And while they all apply to definitions, the details are quite different.
UIKit provides two diffable data source APIs, one for collections and one for tables. Recently, while working on ReactiveCollectionKit, I noticed that the APIs were updated for Swift Concurrency in the iOS 18 SDK, but the annotations were inconsistent with the documentation.
[…]
I reached out to Tyler Fox from the UIKit team on Mastodon to ask if this was a mistake. As it turns out, it is not a mistake and his reply was incredibly helpful and insightful. For posterity and documentation purposes (and because social media is ephemeral and unreliable), I’m going to reproduce his entire response here[…]
These might seem pretty similar – you’d be forgiven for assuming it’s just a convenience to put
@MainActoron the protocol overall rather than having to repeat it for every member of the protocol. Less error-prone, too.But, you generally shouldn’t do that. They are not equivalent.
The first form is not merely saying that all the members of the protocol require a certain isolation, but that the type that conforms to the protocol must have that isolation. The whole type.
Further, as far as the compiler is concerned, there is an actor boundary both going into and returning from
assumeIsolated. This means you cannot work with non-Sendabledata here and that can be an enormous pain.[…]
Before Swift 6.0, dynamic isolation was the only option. And before Swift 6.2, I think that preconcurrency conformances were the best tool for handling protocol isolation mismatches. They address pretty much all of the weakness of the
nonisolated-assumeIsolatedthing. But they just feel funny.[…]
Swift 6.2 allows us to express this idea directly, by constraining a conformance to be valid only for a particular global actor.
What we now have is exactly what we want. A
MainActortype that isEquatablein that context only. This is not the same as a true, unconstraintedEquatable, because those work everywhere. It’s a little like defining a new, special variant of that protocol right in line at the conformance declaration site.[…]
But remember, not all protocols are compatible. And making this entire thing implicit makes the problems even more surprising. Don’t get me wrong, I really like isolated conformances and am very happy to see them come to the language. But they are not a magic bullet (and neither is
MainActor-by-default).
Lukas Valenta at mDevCamp (Mastodon):
The talk focuses - as the name suggests - to strategy to migrate the project from Swift 5 compilation mode to Swift 6. We will discuss several issues anyone will encounter to have project that compiles under Swift 6 mode, such as issues with Combine and Async publishers, DispatchQueue.main precondition queue checks, working with older APIs that predate the concurrency, as well as a debate whether it is all worth it. I will also mention the transition of not only the project itself but also a story of external dependencies, some of which written by me, and how did the migration in the libraries took place.
Previously:
- Swift 6.2: Approachable Concurrency
- SwiftData’s ModelActor Is Just Weird
- Swift Concurrency in Real Apps
- Watch Out for Counterintuitive Implicit Actor-Isolation
- Problematic Swift Concurrency Patterns
- Unwanted Swift Concurrency Checking
- Where View.task Gets Its Main-actor Isolation From
- How the Swift Compiler Knows That DispatchQueue.main Implies @MainActor
- Swift Concurrency Tips
- @MainActor Not Guaranteed
Cocoa iOS iOS 26 Mac macOS Tahoe 26 Programming Swift Concurrency Swift Programming Language