Hello guys!
I'm trying to understand why the code below works not quite as I expect it to work.
What i've tried to achieve is to store weak references to objects with the help of closures. In real world these were delegates and i've filtered out any deallocated instances on every delegate call.
You can see what's happening by putting breakpoint on "print("test")" line.
@main
struct CLI {
static func main() {
var closures: [() -> MyClass?] = []
var strongRefs: [MyClass] = []
var done = false
for _ in 0..<5 {
let instance = MyClass()
strongRefs.append(instance)
closures.append({ [weak instance] in
if done {
print("test")
}
return instance
})
}
for _ in 0..<10_000 {
var temp: [() -> MyClass?] = []
for getter in closures {
if getter() != nil {
temp.append(getter)
}
}
closures = temp
}
done = true
let _ = closures.first?()
}
private final class MyClass {}
}
Stack trace is 20k lines long. All like that:
#19998 0x0000000100002fe0 in thunk for @escaping @callee_guaranteed () -> (@owned CLI.MyClass?) ()
#19999 0x0000000100002f18 in thunk for @escaping @callee_guaranteed () -> (@out CLI.MyClass?) ()
#20000 0x0000000100002fe0 in thunk for @escaping @callee_guaranteed () -> (@owned CLI.MyClass?) ()
#20001 0x0000000100002f18 in thunk for @escaping @callee_guaranteed () -> (@out CLI.MyClass?) ()
Btw, compiling on xcode 15 in release mode stack trace was 30k lines. And since it happened a while ago, now i'm trying to compile in release mode on xcode 16 and not even getting correct result. E.g. "test" is never printed and closures.first?() is nil at the end.
Can someone please explain what's happening here? And maybe provide some resources to read if this is expected behaviour.
I guess it's something to do with a temp array, because closures = closures.filter ... worked as expected (at least with xcode 15).