What would be the most efficient way to forward a declared delegate object’s method to a Xojo event?

Here’s one thing where I couldn’t get my head around:
Say I have a declared macOS object (like in the current case an AVAudioRecorder). It has an optional delegate class with two methods which I’d like to forward as an event.
The basics are easy: Create an own subclass, either from NSObject or from AVAudioRecorder itself if I want to use it directly. The method calls are forwarded to two shared Xojo methods which pick the id delivered from the method, create an AVAudioRecorder (or delegate) object from this handle and, if it’s still alive, invoke a method that raises the event.
So far, everything’s nice and working reliably. Only, while the event raiser does run, the event itself cannot be caught when I create a delegate object on the window or hold the Recorder instance alive in a window property or dictionary and try to use addHandler on it. It simply doesn’t fire.

My usual pattern of approaching such a problem is to install a shared dictionary where the macOS instance looks up itself – the value in this case is a weakref of the connected control or controller class. Then I can invoke the event reliably on the control from the event raiser.
But in general, I don’t like that dictionary handling that much and fear that performance could suffer from having a lot of control/declare object combinations alive.

I wonder if there are any better ways to handle such a problem? I thought of installing an iVar on the class itself but couldn’t figure out how to send the weakref of the connected control to it.

I think there is no other way than having a dictionary of:
Keys: Objective-C Runtime pointers, and
Values: Xojo object instance wrapped in WeakRefs.

Only pointers need to be hashed, which I’m sure is fast. I’d recommend to not use a global dictionary but a shared one on each Xojo class/control/window.

It would be great if a Xojo class instance could be looked up by its internal pointer, then we could use objc_setAssociatedObject and objc_getAssociatedObject and store the reference to the Xojo instance with the Objective-C instance.

can’t you disconnect the logic of the delegate from the delegate itself?
I’m not familiar with the AVAudioRecorder delegates, but with the TextField and TextView delegates I have done something like this, where (WARNING : SWIFT EXAMPLE!!)

the delegate

func textFieldDidBeginEditing(textField: UITextField) { myFunction(textField) }

elsewhere

func myFunction(tf:UITextField) {
do stuff to the textfield
}

the first is called by interaction with the textfield itself, or myFunction is called directly if I want to change things outside of the users purvue.

Or is this not what you were wanting to do?

Thanks, both of you!
@Dave: Eli explained the issue exactly. It‘s not about putting the method handler somewhere else, but forwarding the method call to the Xojo instance that contains the declared object. You won’t find that in Swift. It would be great if one could store the Xojo control’s weakRef in a property of the declared instance. But a Xojo weakRef does not convert to a ptr, and we don’t have access to the Xojo object handle, so the workaround is to store it in a shared dictionary and retrieve the control from there for each “event” (delegate method call). Clearly not the optimum solution but apparently the best working one. Therefore:

Thanks a lot, @Eli! Your reassurance lead me at least to a solution where I can use AddHandler on the declared object that now fires reliably which is much better than the complicated event forwarder I used to use. Next would be some benchmarks to see if brute force (always forwarding inside a Try/Catch statement) or the clean way (checking for a Nil parent object) would be faster.
Do you know if a feedback request for revealing the object handle or the ptr to a weakRef exists?

I believe what Eli described is how macoslib has done it for, like, evar!

I do not really understand what you mean by this. If you mean the dictionary lookup, just:
– test the key for being Nil, if true, create a new Xojo object
– then test to if the WeakRef is Nil, if true, create a new Xojo object
– then test to if the WeakRef’s object is Nil, if true, create a new Xojo object
– else use the object stored in the WeakRef.
I would not use Try…Catch for that. Testing for valid pointers and objects should always be in the form:

If p = Nil Then If obj Is Nil Then

If WeakRef tests to be Nil, you can also immediately remove the pointer from the dictionary. But it is not really necessary when it comes to Xojo controls and windows, or redirected methods of classed create in the Objective-C runtime (like delegates or data sources) as there usually will not be many of them. So as long as you implement the stuff in each Xojo subclass separately, the dictionary with the pointer–WeakRef-of-Xojo-object–mapping will stay small.

Which, frankly, is quite a brilliant approach and I remember spending days looking at that code trying to figure out what the hell they were doing there. Did you encounter any better method?

In general I agree. Some controls, like SpriteKitView or SceneKitView, should fire their events as fast as possible. In those cases, the parent control will exist almost all of the time except maybe for the small period of time where a window containing them would be closed and an event call could fire into Nilvana. So it’s something in the magnitude of a million to one or so, and in those cases I’d prefer the fastest way, even if your advice is good coding practice of course.