0.4 C
New York
Friday, December 6, 2024

Fixing “Reference to captured var in concurrently-executing code” in Swift


Printed on: July 31, 2024

When you begin migrating to the Swift 6 language mode, you may almost definitely activate strict concurrency first. As soon as you’ve got accomplished this there will likely be a number of warings and errors that you’re going to encounter and these errors could be complicated at instances.

I will begin by saying that having a strong understanding of actors, sendable, and knowledge races is a big benefit while you need to undertake the Swift 6 language mode. Just about all the warnings you may get in strict concurrency mode will let you know about potential points associated to working code concurrently. For an in-depth understanding of actors, sendability and knowledge races I extremely advocate that you simply check out my Swift Concurrency course which is able to get you entry to a sequence of movies, workouts, and my Sensible Swift Concurrency ebook with a single buy.

WIth that out of the way in which, let’s check out the next warning that you simply would possibly encounter in your mission:

Reference to captured var in concurrently-executing code

This warning tells you that you simply’re capturing a variable inside a physique of code that can run asynchornously. For instance, the next code will outcome on this warning:

var process = NetworkTask(
    urlsessionTask: urlSessionTask
)

add(fromTask: urlSessionTask, metaData: metaData, completion: { end in
    Process {
        await process.sendResult(outcome) // Reference to captured var 'process' in concurrently-executing code; that is an error within the Swift 6 language mode
    }
})

The process variable that we create a few traces earlier is mutable. Because of this we will assign a distinct worth to that process at any time and that might end in inconsistencies in our knowledge. For instance, if we assign a brand new worth to the process earlier than the closure begins working, we would have captured the outdated process which could possibly be sudden.

Since strict concurrency is supposed to assist us make it possible for our code runs as freed from surprises as doable, Swift desires us to make it possible for we seize a continuing worth as a substitute. On this case, I am not mutating process anyway so it is protected to make it a let:

let process = NetworkTask(
    urlsessionTask: urlSessionTask
)

add(fromTask: urlSessionTask, metaData: metaData, completion: { end in
    Process {
        await process.sendResult(outcome)
    }
})

This transformation removes the warning as a result of the compiler now is aware of for certain that process will not be given a brand new worth at some sudden time.

One other method to repair this error can be to make in express seize within the completion closure that I am passing. This seize will occur instantly as a let so Swift will know that the captured worth is not going to change unexpectedly.

var process = NetworkTask(
    urlsessionTask: urlSessionTask
)

add(fromTask: urlSessionTask, metaData: metaData, completion: { [task] end in
    Process {
        await process.sendResult(outcome.mapError({ $0 as any Error }))
    }
})

Altenatively, you could possibly make an express fixed seize earlier than your Process runs:

var process = NetworkTask(
    urlsessionTask: urlSessionTask
)

let theTask = process
add(fromTask: urlSessionTask, metaData: metaData, completion: { end in
    Process {
        await theTask.sendResult(outcome)
    }
})

This isn’t as elegant however could be wanted in instances the place you do need to cross your variable to a chunk of concurrently executing code however you additionally need it to be a mutable property for different objects. It is primarily the very same factor as making a seize in your completion closure (or straight within the process if there is not any further wrapping closures concerned).

Once you first encounter this warning it could be instantly apparent why you are seeing this error and the way you need to repair it. In digital all instances it signifies that you must both change your var to a let or that you must carry out an express seize of your variable both by making a shadowing let or via a seize listing on the primary concurrent little bit of code that accesses your variable. Within the case of the instance on this put up that is the completion closure however for you it could be straight on the Process.

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles