Some thoughts on the Responder Chain

And some rant

I had a lot to do these days and did not manage to keep up with the blog. Very busy time at the office before Christmas. Luckily, I’ll get my vacation soon by I swear I will not spend it on much anything else than reading paper books. And books which are not about programming, project management or anything even remotely from what I do for a living.

However, I made some progress on my USBTMC driver. While digging the net for some documentation, I ran into a bunch of discussions about the responder chain. And I was puzzled by some replies and about the deep misunderstanding on what this very simple — yet powerful — concept is about. So allow me some words on this.

Let me begin with a rant. On forums, folks that answer by “use the search feature, this topic was beaten to death” or (more poetically) “~was discussed ad–nauseam” bring me on the brink of throwing up. I will never take an advice from somebody that writes such crap. This is simply because that person is obviously much more interested in listening to oneself instead of honestly helping. I agree, all situations when same topics and same questions are raised over and over again might be irritating. But being nervous or getting irritated is simply an issue of perception and personal choice. The root cause of a doubt might be attributed to some crooked approach towards reasoning and understanding a concept or might be a consequence of poor documentation, or might be simply because one cannot find a satisfactory answer after several forum searches. And I would vote for the latter. The same experts bring up the same boilerplate answers to simple questions, a fact that, per se, is much more closer to the ad–nauseam organic reaction than the questions themselves. One good example (encountered in five different posts, around ten times in each post): “responder chain allows proper decoupling”. Shit like this does not help. And if I get such proof by assertion each and every time, I would ask the same question again and again: “Ok, decoupling. I understand. But why using a responder chain design pattern ?” Simply because decoupling is not the rationale behind each and every software architecture reasoning and design decision. And, more importantly, it was definitely not the reason that triggered invention of the responder chain (as a concept and design pattern). But decoupling is a cool and trendy word. So let’s use it. Ad–nauseam.

A short definition

In very few words, I am trying to explain what is this about. Of course, you can read much more on this page, but here I am just trying to make a very simple point and make you understand one very simple thing: the responder chain was invented to solve the problem of routing user input to the right UI component. Period ! Say that again:

The Responder Chain was invented to solve the problem of routing user input to the right UI component.

Of course, there are some other very important advantages and consequences like decoupling, or cooperative event handling, or providing support for context–sensitive features, menu item enabling, error handling etc; however the responder chain was born with one simple and clear purpose in scope: to simplify this unbelievable logistically–difficult task, of dispatching your actions, as user, (i.e. mouse clicks, mouse moves, keyboard entry etc etc) to the right interface element.

Why ? Think about this: when the user is focused on a particular user interface element, as the user focus changes, the target needs to change dynamically to follow the focus. The idea behind responder chain implementation is extremely simple: it is based on a chain of responsibility. A message or event is passed from one object linked to another until one of them handles the message.

The first consequence is that any object within this chain has an opportunity to handle or to ignore the message. Since, in cocoa, any entity is an object and each object type can be dynamically determined at runtime, this mechanism is extremely powerful and very flexible.

How is this possible ?

There is no magic here but probably an example will make it a bit clearer. Although I will not get into the actual detail of how this is implemented in the runtime (maybe in a future post), there is something that should be said: a very important thing to remember is the fact that whenever an user provides some input to an object, that object can respond to the input only if inherits from NSResponder class. Because NSApplication, NSWindow and NSView classes are all subclasses of NSResponder, the majority of classes encountered in Cocoa are responders. This is illustrated in this drawing from Apple’s AppKit Framework Reference.

All items above are subclasses of NSResponder. Basically there is no user control that does not inherit from NSResponder.  As an user interacts with an application, the Cocoa framework tracks the user focus. The currently focused document/ window is the main window. The window that receives keyboard input from user is the key window. In the vast majority of situations, the main and the key windows are the same. But there are applications where these two might be different. Think about an app that has a document window and some panels with edit features, for example font selection. The document will be the main window, but, if the user chooses to change the font, the key window will be the font panel.

Both the main and the key window are tracked by the application object. References to these can be obtained from the NSApplication instance with the -keyWindow and -mainWindow messages:

NSWindow *keyWindow = [NSApp keyWindow];
NSWindow *mainWindow = [NSApp mainWindow];

Ok, that’s it. Today’s dose of Cocoa wisdom. I leave you the pleasure to discover the beauty of the documentation and read more about this. But when you get confused reading too much of similar wisdom, just close your eyes and mumble this:

The Responder Chain was invented to solve the problem of routing user input to the right UI component.

 
 

Leave a Reply

Your email address will not be published. Required fields are marked *