Give your simulator superpowers

RocketSim: An Essential Developer Tool
as recommended by Apple

Win a copy of The macOS App Icon Book with thisfree giveaway

@preconcurrency: Incremental migration to concurrency checking

The @preconcurrency attribute is part of the tools that help you incrementally migrate to strict concurrency checking. When async/await was introduced by Apple, we were writing non-structured asynchronous code, mainly using closures. On our road to Swift 6, we must prepare our projects for strict concurrency checks done by the compiler. The SE-0337 proposal makes it possible to migrate incrementally.

Before diving into the details about the attribute, I encourage you to read the following articles:

Those articles introduce you to Swift Concurrency and help you better understand why we need to think about managing pre-concurrency code.

What is the @preconcurrency attribute?

Like @unchecked Sendable, the @preconcurrency attribute helps you silence concurrency-related warnings without implementing Sendable conformance. While updating your codebase to make use of the latest concurrency changes, you might have been running into the following warning:

Add ‘@preconcurrency’ to suppress ‘Sendable’-related warnings from module ‘<some module>’

The Xcode compiler recognizes 3rd-party modules that are not in your control. In other words, libraries that you can’t easily migrate to work with Swift Concurrency. In those cases, you can suppress warnings triggered from those libraries by using the @preconcurrency attribute before an import:

@preconcurrency import Auth0

The compiler will no longer trigger warnings related to code from this specific library. While adding the attribute and getting rid of many warnings is easy, it’s essential to understand the risks you take.

Stay updated with the latest in Concurrency

The 2nd largest newsletter in the Apple development community with 19,200 developers. Don't miss out – Join today:

You can always unsubscribe, no hard feelings.

The risks of using @preconcurrency

In an ideal world, there should be no risks when adding the @preconcurrency attribute. If the library owners did a good job, all their code is thread-safe, and they prevented data races by synchronizing access.

However, it could also be that none of the code is thread-safe. Usually, we would be warned by the compiler due to missing Sendable conformance:

Capture of ‘highlight’ with non-sendable type ‘SWHighlight?’ in a @Sendable closure

These warnings will no longer be triggered since we marked the library as a pre-concurrency import. You are taking ownership of ensuring thread-safe code. Keep this in mind when adding the attribute and try to see if an alternative solution is available, like updating the dependency to a newer version that possibly supports concurrency.

Should I import all 3rd party libraries using @preconcurrency?

Importing all 3rd party libraries using the @preconcurrency attribute by default might be tempting. However, if there’s no need to import a library to prevent concurrency warnings, it’s better not to do it. The compiler will warn you if you’ve imported a library using the attribute for no reason:

‘@preconcurrency’ attribute on module ‘Alamofire’ is unused

By not using the attribute and keeping the warnings visible, you allow yourself to revisit the code in the future when a fix from the 3rd party maintainer might be available. Suppressing the warnings can feel like a great solution today, but it will also hide possibly vulnerable code in your project.

Revisiting pre-concurrency imports regularly

If you decide to use the @preconcurrency import, planning a revisit of your code is essential. Once the library maintainers add support for concurrency, you can remove the attribute and see whether new warnings appear in your code that you need to fix. Any Sendable-related failures involving that module will no longer suggest the @preconcurrency import and will result in errors once using Swift 6.

Continuing your journey into Swift Concurrency

The concurrency changes are more than imports and include many new features you can benefit from in your code. Now that you’ve learned about pre-concurrency maintenance, it’s time to dive into other concurrency features:

Conclusion

The @preconcurrency attribute works excellently to temporarily suppress warnings for libraries that are out of your control. It’s essential to be aware of the risks it brings since you’ll no longer get Sendable-related warnings. You should plan a revisit of your pre-concurrency imports to make sure you’re updating your code once a concurrency-supporting alternative becomes available.

If you like to learn more tips on Swift, check out the Swift category page. Feel free to contact me or tweet me on Twitter if you have any additional suggestions or feedback.

Thanks!