This post originated from an RSS feed registered with Agile Buzz
by James Robertson.
Original Post: Round Trip Events
Feed Title: Travis Griggs - Blog
Feed URL: http://www.cincomsmalltalk.com/rssBlog/travis-rss.xml
Feed Description: This TAG Line is Extra
Much thanks to Sames for this one. I had a recent scenario which involved one view (event consumer) and many objects (event sources) it was observing. At first blush it was not quite as easy to set up this scenario as it had been with c/u (changed:/update:). With c/u I would've just created the case statement obimination and used the third argument off of update:with:from: to figure out who I was getting the event from.
You can set your consumers event handler to include information like this:
This works fine, until you've caused the event source (theObservedObject in the above) to already include some information in addition to the event, something like:
What happens is that when the method respondToChangeIn: gets sent, theObservedObject will NOT be what you get as your argument, you'll get the someData that came from theObservedObject.
Luckily, we have other ways of setting up handlers. We can use something like:
Problem solved! Kind of. Now the next part of the problem comes along. How do we clean these things up? In many cases, you don't care. The life cycle of the source and consumer is the same and they and the graph created by their interconnected event triggering can just all go away together. I was not so fortunate. My event sources were long lived. And the consumers (one or many) could come and go arbitrarily at will. The last thing you want in a case like that is one where the view gets created, then closes, but is kept alive (ergo, it is not GC'ed) because its still recieving events from the source. This means we want to somehow do something like:
Even if we could've got the original to work, this is a problem. It requires our consumer to not only build a handler for the source, but to remember the source (in an ivar or something) so that we can remove them in a release method. Now our actions are blocks (for those that seem to fear blocks, you can use a MessageSend if that eases your closure indigestion a little), and we've got to remember those.
This was where Sames entered the picture and shared the zen masters sense of event-ness with me. C/u, especially with its roots so tied to MVC, is always very unidirectional in event flow. Very client/server-ish. Events seem to encourage a more peer to peer mind set of event flow. The trick is to have the source and consumer flip roles. Cause the consumer to trigger a #release event, and then create handlers for this event which clean things up. With our original consumer object now also triggering events, we can set the whole thing up in one method, something like:
The more I use events versus c/u, the more I like them. One could argue (I have) that technically they and c/u are really no different. Technically, that's probably true. But then, that's like arguing that Java and Smalltalk are both turing complete. I find with events, I'm encouraged to use different (that means better in this context) idioms and approaches than I would with c/u, and that ultimately I wrote smaller/simpler object interactions, and that's a good thing. Thanks again Sames!