Warning: Reference to captured var 'hashBag' in concurrently-executing code

I get many warnings like this when I build an old project.

I asked AI chatbot which gave me several solutions, the recommended one is:

var hashBag = [String: Int]()
func updateHashBag() async {
var tempHashBag = hashBag // make copy
await withTaskGroup(of: Void.self) { group in
group.addTask {
tempHashBag["key1"] = 1
}
group.addTask {
tempHashBag["key2"] = 2
}
}
hashBag = tempHashBag // copy back?
}

My understanding is that in the task group, the concurrency engine ensures synchronized modifications on the temp copy in multiple tasks. I should not worry about this.

My question is about performance.

What if I want to put a lot of data into the bag? Does the compiler do some kind of magics to optimize low level memory allocations? For example, the temp copy actually is not a real copy, it is a special reference to the original hash bag; it is only grammar glue that I am modifying the copy.

Answered by DTS Engineer in 833584022

Using a task group to protect a hash table is unlikely to yield sensible results. As to what would be better, it’s hard to say without knowing more about the context. You could, for example:

  • Confine access to this hash table to the main actor.

  • Or embed it with a custom actor.

  • Or protect it with Mutex.

If you explain more about the big picture, we should be able to suggest a more concrete path forward.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

A few things here:

  1. STOP asking "AI" for answers to your coding issues. They are rarely correct, and just lead you down a rabbit hole of nonsense.
  2. I have absolutely no idea what you're trying to achieve here.

Perhaps, stop using AI to craft your questions, and ask a proper question that we might be able to understand...? What are you trying to achieve? What is YOUR code? What error are you seeing in YOUR code?

Using a task group to protect a hash table is unlikely to yield sensible results. As to what would be better, it’s hard to say without knowing more about the context. You could, for example:

  • Confine access to this hash table to the main actor.

  • Or embed it with a custom actor.

  • Or protect it with Mutex.

If you explain more about the big picture, we should be able to suggest a more concrete path forward.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I have found the solution myself. It's actually straightforward, set project min platform to 10.15 and I can do this without warnings anymore:

Task {
bagLock.lock()
hashBag["file"] = hash
bagLock.unlock()
}

Actor is too heavy for this scenario because I have several variables like this in an async function; Mutex is quite new and my project has to target a much older platform like 10.15 which enables me to use Task async.

Again, it’s hard to offer detailed advice with such a small code snippet. For example, what are you using for the lock? However, in general:

  • You are correct that spinning up a task for small snippets of code is inefficient, and in that case a lock is often a good option.

  • I recommend Swift’s built-in Mutex, but if you have to deploy back to older systems then use OSAllocatedUnfairLock and, if that’s not old enough, NSLock.

  • When working with locks, it’s good to use the ‘with’ pattern. That way you guarantee that the lock is always released. Mutex, OSAllocatedUnfairLock, and NSLock all support this pattern out of the box. For example, the withLock(_:) method on Mutex and similar methods on the other types.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Warning: Reference to captured var 'hashBag' in concurrently-executing code
 
 
Q