26.1 C
Canberra
Monday, February 24, 2025

Fixing “reference to var myVariable isn’t concurrency-safe as a result of it entails shared mutable state” in Swift


Revealed on: August 15, 2024

When you begin migrating to the Swift 6 language mode, you will most certainly activate strict concurrency first. As soon as you’ve got finished this there will probably be a number of warings and errors that you’re going to encounter and these errors might be complicated at instances.

I am going to begin by saying that having a strong understanding of actors, sendable, and knowledge races is a large benefit while you need to undertake the Swift 6 language mode. Just about the entire warnings you will get in strict concurrency mode will inform you about potential points associated to working code concurrently. For an in-depth understanding of actors, sendability and knowledge races I extremely suggest that you just check out my Swift Concurrency course which can get you entry to a collection of movies, workout routines, and my Sensible Swift Concurrency guide with a single buy.

WIth that out of the best way, let’s check out the next warning that you just may encounter in your challenge:

reference to var myVariable isn’t concurrency-safe as a result of it entails shared mutable state

There are a number of causes for this warning to pop up in Xcode. For instance, the code under would trigger Xcode to warn us:

// Var 'myVariable' isn't concurrency-safe as a result of it's nonisolated international shared mutable state; that is an error within the Swift 6 language mode
var myVariable = UUID()

func randomCharacter() async -> Character {
    myVariable = UUID()
    return myVariable.uuidString.randomElement() ?? "1"
}

The next code makes myVariable a static var which ends up in the identical warning being proven:

struct CharacterMaker {
    // Var 'myVariable' isn't concurrency-safe as a result of it's nonisolated international shared mutable state; that is an error within the Swift 6 language mode
    static var myVariable = UUID()

    static func randomCharacter() async -> Character {
        myVariable = UUID()
        return myVariable.uuidString.randomElement() ?? "1"
    }
}

The Swift compiler considers any globally accessible var to be unsafe from a concurrency viewpoint. The rationale for that’s that nothing is stopping us from making a number of calls to randomCharacter concurrently which might lead to a knowledge race on myVariable. We might find yourself with a number of learn and write operations on the similar time.

To repair this, myVariable ought to both be moved into an actor or be remoted to a worldwide actor.

For instance, you possibly can isolate myVariable to @MainActor like this:

// with a worldwide variable
@MainActor
var myVariable = UUID()

// or as a static property
struct CharacterMaker {
    @MainActor
    static var myVariable = UUID()
    // ...
}

The draw back of that is, after all, that we must be on the primary actor to work together with the variable. You’ll be able to work round this by defining your individual (empty) international actor which can make sure that our accesses are on the worldwide executor as an alternative of the primary actor:

@globalActor
actor GlobalIsolator {
  static let shared = GlobalIsolator()
}

@GlobalIsolator
var myVariable = UUID()

// or as a static property
struct CharacterMaker {
    @GlobalIsolator
    static var myVariable = UUID()
    // ...
}

This makes accessing myVariable a bit much less handy since you’ll want to put your self on the GlobalIsolator actor when interacting with myVariable:

@GlobalIsolator
static func randomCharacter() async -> Character {
    myVariable = UUID()
    return myVariable.uuidString.randomElement() ?? "1"
}

In some circumstances you will know that despite the fact that the compiler would not like your shared mutable state, you know that it is fantastic because of the method your code is structured.

If that is the case, and also you’re completely 100% certain that you just will not have any points associated to your shared mutable state, you should use nonisolated(unsafe) in your variable to inform the compiler that the dearth of isolation is intentional and that you just’re conscious of its knowledge issues of safety:

// with a worldwide variable
nonisolated(unsafe) var myVariable = UUID()

// or as a static property
struct CharacterMaker {
    nonisolated(unsafe) static var myVariable = UUID()
    // ...
}

You must solely use nonisolated(unsafe) as a last-resort resolution as a result of the compiler will not give you the chance that will help you detect potential knowledge races round myVariable.

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

[td_block_social_counter facebook="tagdiv" twitter="tagdivofficial" youtube="tagdiv" style="style8 td-social-boxed td-social-font-icons" tdc_css="eyJhbGwiOnsibWFyZ2luLWJvdHRvbSI6IjM4IiwiZGlzcGxheSI6IiJ9LCJwb3J0cmFpdCI6eyJtYXJnaW4tYm90dG9tIjoiMzAiLCJkaXNwbGF5IjoiIn0sInBvcnRyYWl0X21heF93aWR0aCI6MTAxOCwicG9ydHJhaXRfbWluX3dpZHRoIjo3Njh9" custom_title="Stay Connected" block_template_id="td_block_template_8" f_header_font_family="712" f_header_font_transform="uppercase" f_header_font_weight="500" f_header_font_size="17" border_color="#dd3333"]
- Advertisement -spot_img

Latest Articles