snowcone-ltd / libmatoya

Cross-platform application development.
MIT License
578 stars 50 forks source link

Properly register Objective-C class for NSView #100

Closed dvijayak closed 1 year ago

dvijayak commented 1 year ago

The problem was due to the fact that our custom view class was not registered with the runtime. Apple's documentation clearly states that when a class has been allocated and its methods and what not set, the final step before using the class is to register it with the runtime by calling objc_registerClassPair. Not heeding this results in undefined behavior, one of those being the crash we witnessed.

Precisely how that led to the crash

Objective-C runtime offers a unique feature called Key-Value Observing (KVO) where you can observe for changes on properties of any derived class of NSObject as long as the property meets the definition criteria. It turns out that the Webkit implementation under the hood makes use of this in some blackbox manner in order to implement docked windows, which is used for the Developer Tools window of the WebView when it is docked.

Well, the way KVO is implemented under the hood is that the runtime calls objc_duplicateClass on the class being observed in order to clone this class and dynamically create a new class from this and setup the machinery required for the key-value observation to work. My strong suspicion is that this call will fail if the class has not been registered. Perhaps according to the runtime, a class that is not registered doesn't exist for practical purposes. (The fact that it works for most things that we have encountered so far except this KVO thing is really annoying...it would have been much more helpful had the app crashed much earlier with a more helpful description so that we could have caught this much earlier...but that's apple engineering for you).

What further confirms the above hypothesis is the following exception logged when running the app under lldb:

2023-04-21 01:05:31.916943-0400 parsecd[37300:14529429] [general] KVO failed to allocate class pair for name NSKVONotifying___mty_app_view_0, automatic key-value observing will not work for this class

objc[37300]: no class for metaclass 0x600000c214d0

The runtime tried to clone our view class in order to create the KVO clone as discussed earlier but it failed to allocate it due to the reason no class for metaclass. This strongly hints that it couldn't FIND the class, which would make sense if the class wasn't registered. QED