NickZemlin
(Nikita Zemlin)
1
Hello, I have a question regarding how exactly does Swift handle closure capture context when 2 closures capture the same instance of a value type, in this example string.
struct someStruct {
func someFunction() {
var someVariable = "some variable"
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
someVariable = someVariable + " mutated" // mutates captured value type
}
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
print(someVariable) // prints "some variable mutated"
}
}
}
someStruct().someFunction()
My assumption ( based on that comment ) is that both closures share the same closure context from their parent scope.
Could you please share some resources that can help with that question?
Additionally, I have two more questions:
- When does the variable ‘someVariable’ get deallocated from the stack?
- How does it get shared between two closures?
1 Like
tera
2
I'd recommend you to consider a simpler example with Int instead of String. Int is a pure simple value type so the analysis won't involve having to deal with all of these:
- a separate heap allocated object for the string contents
- COW
- small string optimisation (strings up to 15 bytes stored inline)
With a simpler Int:
someVariable will not be allocated on the stack in this case but on the heap. If you want to drill to how exactly this is played out in memory - you'd need to start with a closure:
struct Closure {
var functionPointer: UnsafeRawPointer
var closureContext: AnyObject?
}
e.g. define your own
func foo(_ closure: @escaping () -> Void) {
// dump closure bytes to see its layout #2
closure()
}
and call it similarly to how you call dispatch queue:
func someFunction() {
var someVariable = 0x123456789ABCDEF0
// dump the address of someVariable here #1
foo {
someVariable += 1
}
}
I bet at some point you'd see the address of the variable obtained in #1 while analysing #2.
3 Likes