Understanding dyld messages around a missing symbol

I have two frameworks, with one dependent on the other. The calling framework is hitting a dyld: missing symbol called error and crashing the app.

dyld doesn't report what symbols it is, but I've traced it to a call to Heap.shared.addSource(a, isDefault: b)

Using DYLD_PRINT_BINDINGS=1, I get this interesting output:

dyld[95410]: <.../bind#135> -> 0x103fcafb4 (HeapSwiftCore/_$s13HeapSwiftCore0A0C6sharedACvgZ)
dyld[95410]: <.../bind#137> -> 0x1802bfda0 (libdyld.dylib/_$s13HeapSwiftCore0A0C9addSource_9isDefaultyAA0E0_p_SbtFTj)

All non-static members of the Heap class are marked as coming from libdyld.dylib, rather than the correct module. (I'm assuming this is the cause of the missing symbol.)

If, in the app itself, I call the method directly, the call from the app succeeds and the binding is set to the correct module.

dyld[95410]: <BadDYLD.debug.dylib/bind#8> -> 0x103fcbf30 (HeapSwiftCore/_$s13HeapSwiftCore0A0C9addSource_9isDefaultyAA0E0_p_SbtF)

Am I right in my assumption, that the log message is reporting the true issue. And if so, what could cause the symbol to load incorrectly like that?

As an update:

I have a protocol HeapProtocol that has all the public members of Heap, and the following workaround works:

let heap: HeapProtocol = Heap.shared
heap.addSource(a, isDefault: b)

It appears the issue was actually introduced by changing the class from @objc public class to @objc final public class.

I actually get a build issue when switching from an older working version to the broken one without cleaning:

1 Like

Yep, adding or removing final is an ABI breaking change.

1 Like

Ah, all the pieces are coming together now. Thanks @Slava_Pestov.