Swift developer Matt Massicotte has accumulated a wealth of experience throughout his career, including work at Crashlytics and Apple, and has built a GitHub code repository based on these experiences. This code repository integrates many practical tips to make it easier for developers to harness Swift’s concurrency capabilities. These materials not only help solve common problems but also highlight some potential pitfalls that people may encounter during the programming process.
With the introduction of async/await and support for actor in Swift 5.5, Swift’s concurrency programming capabilities have been significantly enhanced, and complete data isolation and structured concurrency were realized in Swift 5.10. Although these are exciting advancements, learning and mastering all these new concurrent features has become a huge challenge, especially since Swift’s concurrency mechanisms need to work in conjunction with earlier technologies and libraries, such as Grand Central Dispatch (GCD).
Against this backdrop, the project library established by Massicotte aims to include solutions and explanations of potential pitfalls that might be needed when transitioning to Swift concurrency and phasing out GCD. He strongly believes that documenting and sharing these experiences and warnings can greatly benefit the developer community. At the same time, he welcomes more developers to join in the exploration, contribute, especially in terms of raising issues.
The code repository is divided into multiple sections, each focused on a particular topic. They cover topics ranging from creating basic tasks for an asynchronous programming environment to broader issues such as handling protocols, isolation, SwiftUI, and more. For example, Massicotte shared complex situations dealing with concurrency in SwiftUI. He pointed out that only the body accessor of a SwiftUI view is guaranteed to be safely executed on the MainActor, while other functions or properties declared in the view do not ensure isolation, and may lead to race conditions. To solve this problem, he suggests explicitly using the @MainActor
attribute for properties of more complex views:
@MainActor
struct MyView: View {
var body: some View {
Text("Body")
}
}
Similar issues also exist in the concurrent handling of protocols. Massicotte has explained the complexity you might encounter when you try to conform a type, which is already isolated as a MainActor, to a protocol that you can’t fully control the definition of. Here, you need to pay special attention, because while an actor needs to ensure that its state can only be accessed from outside via async methods to prevent race conditions, if an actor-isolated type must conform to a protocol that includes non-async methods, then careful consideration is needed.
When dealing with concurrent programming, one recommended simpler approach is to use the nonisolated
keyword, which directs the compiler to adopt a “non-isolated” consistency model. Also, a viable alternative is to use delegation to avoid such problems. As mentioned before, many potential issues and possible solutions are described in detail.
Although the solutions recommended by these code libraries to date may not be perfect, they undoubtedly enhance the developer’s understanding of possible error conditions when using Swift for concurrent programming, making it a very valuable resource.