Happy New Year! One of the things I want to do this year is post more short, regular content. A friend of mine is learning Mac programming, so to help out, I’m planning to write short snippets that explain bits of Cocoa (The Mac OS X programming framework) that I didn’t “get” the first time round. Often, the concepts aren’t that difficult, and often I already knew them by other names, but didn’t make the connection. I just didn’t really find the official explanations as helpful as they could be.
Like I did when I started, he knows C/C++ but not Objective-C, so the explanations are tailored accordingly. Hopefully it’ll help some other people too.
First up: Selectors.
(Selectors aren’t technically part of Cocoa but they’ll crop up in Cocoa discussions, so it’s useful background for upcoming posts.)
Objective-C’s object-orientation model is heavily influenced by that of Smalltalk. Some of this just leads to terminology or syntax changes, but some affects the behaviour.
For instance, dynamically/polymorphically dispatching methods to objects: In C++ this is all about the Virtual Method Table. Lets say you want to iterate across a list of objects, of differing classes, calling the render() method on each of them. To do this in C++, they need to share a common ancestor class that declares render() as a virtual method. This is not only enforced by C++‘s type system, but also a technical limitation: Without the common ancestor, they’re not guaranteed to have a common VMT entry. No VMT entry, no polymorphic dispatch. C++ looks up which slot of the VMT render() belongs in at compile-time, so the code for calling it amounts to “go to slot n of this object’s VMT and call the function pointer you find there.”
At compile-time, a call in Objective-C only looks up the selector of the method/message. This is, in effect, the name of the message in a form that can be passed around and inspected at runtime. A selector is the same for all methods that have the same name and parameters – regardless of which objects define them, whether those objects are related in the class hierarchy, or actually have nothing to do with each other. At runtime, Objective-C goes to the class and outright asks it, “Do you respond to this selector?”, and calls the resulting function pointer if it does.
Much of the time, you just get on with the business of calling the method (or “sending a message” to the object, in Objective-C/Smalltalk parlance), and let the runtime worry about what’s going on behind the scenes. If the object (“the receiver of the message”) doesn’t actually have that method (“doesn’t respond to that message”), the runtime simply returns null.
But you can look up a selector yourself, to store or pass around. They are often used for callbacks: A timer or notification will often take both a selector, and a class instance to send it to. In this way, they are often used like function pointers in C. The callback receiver doesn’t need to be of any particular class, or implement any particular interface (in the Java sense). The result is very similar to Python’s “duck typing”.
You can also explicitly ask objects if they can receive the selector, just like the Objective-C runtime does. This can be used for “chain of command” patterns, where you have a sequence of objects and ask each one in turn if they respond to the selector until you find one that does.
The data type of a selector is SEL and you use the @selector() operator to look one up by hand. Remember to include all parts of the method name, including all colons!
SEL theRenderSelector = @selector(render:);
if ([someObject respondsToSelector: theRenderSelector])
{
// ...
}
In the next part, we’ll see the role selectors play in event handling.