Running the code below usually prints:
hello
Occasionally, it prints:
hello BlockExperiment world
But sometimes I get the following crash:
hello BlockExperiment/usr/bin/swift[0x51f95a4]
/usr/bin/swift[0x51f719e]
/usr/bin/swift[0x51f987c]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x12980)[0x7fc7c0650980]
/usr/lib/swift/linux/libswiftCore.so(+0x40d2c4)[0x7fc7bc9642c4]
/usr/lib/swift/linux/libswiftCore.so(+0x3fecc6)[0x7fc7bc955cc6]
/usr/lib/swift/linux/libswiftCore.so(+0x3fe20b)[0x7fc7bc95520b]
/usr/lib/swift/linux/libswiftCore.so(+0x3e456d)[0x7fc7bc93b56d]
This doesn't seem to break any of the weak/strong/unowned practices that I know of.
Is the problem a basic race condition, where self is being accessed in the print statement after it has already been deallocated?
I can't be sure because in that case, I would expect the usual error message saying the access was to a deallocated instance. If it isn't this, how can you tell and in general debug this type of issue?
And if it is a race condition, why does the print statement get cut off sometimes after "hello"?
Code:
import Foundation
final class BlockRunner {
var block: () -> ()
init(_ b: @escaping () -> ()) { block = b }
func run() { block() }
deinit { print("Deinit: \(self)") }
}
final class BlockExperiment {
func f() {
let queue = DispatchQueue(label: "Queue")
let runner = BlockRunner { print("hello", self, "world") }
queue.asyncAfter(deadline: .now() + 1) { runner.run() }
}
deinit { print("Deinit: \(self)") }
}
do {
let e = BlockExperiment()
e.f()
RunLoop.current.run(until: Date() + 1 + 0.000000000000001)
}