I’m working on our app’s internal event subscription and distribution mechanism.
The idea is fairly straight forward. Objects (UI controls / windows or non-UI) subscribe to receive events (callbacks) of a particular type. In other areas of the app events are raised and the subscribers all receive callbacks.
In order to uniquely identify the subscriber, I’ve found I need to send the subscriber object along with the callback method when subscribing. Of course, this means that the event handling system needs to hold onto both the object reference AND the callback reference in order to a) perform the callback when needed and b) identify if the object has been destroyed and the callback should not be invoked.
I use WeakRef in order to hold onto the subscriber object and am experimenting with weakAddressOf for the callback but nothing seems to allow the subscriber object to be destroyed when it should be. I can strive for proper unsubscribing by all subscribers but it seems my event handler still stumbles across situations where the weakRef’s .value is still set and the callback is not nil and I can’t seem to do anything other than catch the exception when its .invoke is called. This seems messy and dangerous, not to mention potentially memory leaking…
I’ve discovered Guyren Howe’s method of creating a hash of the object for more effect dictionary storage but a complete solution evades…
am I missing something obvious here?
please take a look at the Notifier pattern in the example projects.
I think this can be very useful for your case as an alternate, simpler and elegant way to do event distribution without “invoke” and similar stuff.
The pattern it’s based on “interface” as a way to extends existing classes and objects.
Thanks. I think you must mean the Observer project in Design Patterns?
It’s a reasonable example of an Observer pattern but unfortunately suffers from the very problem I am referring to. The windows that are created and added to the array in the main window never lose all their references (even if they are closed) so they hang around indefinitely. It’s a huge memory leak.
Also, it shows the interface mechanism alright but otherwise isn’t nearly as oop as what I am working on. Each item that notifies has to keep track of all that want to be notified. In a situation where all who want to be notified will want to be notified about newly added objects, the pattern breaks down.
but thanks for the response. I’m hoping someone has worked their way through this before…
I’ve done things like this before and say it should work, you must have a ref or cycle you don’t know about. Can you post a simple demo of your event bus class?
I have made a little progress as I was passing ‘self’ in one case rather than ‘me’ so the observer object was accidentally the window rather than the control as desired. This seems to have allowed it to be destroyed which is detectable… still I wonder if I’m going to have problems when I want windows to be able to observe…
Does anyone know if references to methods (i.e. delegates) are also counted? They are particularly squirrelly - if they are an instance method they implicitly contain a ‘self’ reference but that reference is undetectable so they are indistinguishable from other instance’s methods.
They are counted, unless you use WeakAddressOf. The trick to using weak delegates, and maybe you alluded to this, is you can’t directly tell when their targets have gone nil. You want to either wrap all weak delegate invokes in a try/catch or keep a WeakRef to the methods instance and test that first. With everything ‘weak’ they should all go nil, including if it’s a window. Without some code it’s difficult to diagnose.
Why would you hold a reference to a delegate? Seems like an interface and weak object references are the order of the day.
@Will Shank: thanks for the reply. An interesting thing I’ve just noticed. When I use WeakAddressOf to pass the delegate on subscription and then again when unsubscribing, the WeakAddressOf value appears to be unchanged. This aids greatly in finding the subscription references and unsubscribing. It was an unexpected benefit that I hope remains constant…
It’s a powerful thing to be able to disconnect the observed and observers in such a way. It allows scoping & filtering in the event manager and has a low overhead… that said, it may be easier to do it using interfaces. That’s part of the reason I posted my question.
thanks for the responses.
In my program I was originally using interfaces for a subscriber system (but I was probably doing something wrong) and ended up coming up with this XFNotificationCenter that is mirrored slightly on NSNotificationCenter… Probably not the best thing in the world, but it does seem to work pretty well for me…
Thanks! I will take a look. I may have worked out my issues so far, but I have no doubt something else will crop up.
I’m a little late to the party, but a while back I developed an event bus that (to the best of my knowledge) doesn’t suffer from the issues you are seeing.
There’s a couple of small example projects for it, they show the cleanup mechanism in action too, which might be of interest to you.
It’s open source (MIT license), so feel free dive in and knick anything of use.
The event bus uses a strict mechanism for the “callback” which is probably not to your liking (subscriber must implement an interface that includes a known function name as the callback so we don’t have to pass it in), but I still think you’ll find it an interesting read (it’s quite small if you disregard the Web Edition session casting code and concentrate on the desktop stuff).
If you do find problems with it please give me a shout, it’s about time I had another look at the projects anyway (although I’m pretty sure they are stable and “just work”)!