Consider the following example:
import Foundation
func qux() { print("Q_U_X") }
func zab() { print("Z_A_B") }
class Foo: NSObject {
deinit {
qux()
}
}
class Bar: Foo {
deinit {
zab()
}
}
Code generated for Bar.deinit() uses objc_msgSendSuper2 to call [super dealloc]. Call finds $s3foo3FooCfDTo (aka @objc foo.Foo.__deallocating_deinit), which has an extra selector argument. It ignores that argument and then calls $s3foo3FooCfD (aka foo.Foo.__deallocating_deinit).
Why not just bypass ObjC machinery altogether and call $s3foo3FooCfD directly?
For async deinit, FooCfD is a thunk that creates task and runs asynchronous FooCfZ (aka foo.Foo.__isolated_deallocating_deinit) in that task.
So far, I've ended up with implementation where asynchronous $s3foo3BarCfZ (already running inside a task) calls [super dealloc] using objc_msgSendSuper2. This calls $s3foo3FooCfDTo, which in turn calls $s3foo3FooCfD, which creates a new task and runs $s3foo3FooCfZ there.
That sounds very inefficient. I want to call async $s3foo3FooCfZ directly from async $s3foo3BarCfZ, which is not possible (or at least hacky) using ObjC machinery.
Are there any reasons why Swift deinit need to use ObjC machinery if base class is known to be a Swift class?