Friday, 9 May 2014

iOS/Objective-C Unrecognized selector sent to instance

Further to my earlier rant about Objective-C and how it mostly sucks, here is another error that most of us have probably seen. Unfortunately, it is worded in a way that assumes you understand the specific terms used in Objective-C like messages, selectors, actions etc. none of which are familiar to people from a C background despite the claims by the Apple fanbois that Obj-C is just a superset of C.

Selectors and Objective-C

In plain English, this error message means that a message was passed to an object and the message did not have a matching handler. What am I talking about? Well in normal C/C++, you would call a function/method either on an object or in the global namespace. The compiler will fail if it cannot link the call to the function itself. In Obj-C, for some reason, they have chosen a message based system, so you are not calling functions but sending messages to objects (that's all that horrible square bracket and colon stuff), which allows you to pass messages that are not actually present in the target object since you might be handling these at runtime. As with any late-bound language, this means that things will compile and potentially fail at runtime and the most common error is what you can see above.
Error Example
See the code below. The top block shows the method (or message handler) defined in a class and note that it takes one parameter. The second block calls this method but does not pass the parameter expected.

-(void) doSomething:(UIView*)view
{
    // Do something here
}
-(void) someOtherFunction
{
    [self doSomething];    // Error at RUNTIME - unrecognized selector sent to instance
    [self doSomething:nil];    // OK since parameter is passed
}

It gets worse!

I had another error of the same sort but in this case, I was passing the name of a function to @selector() to be used as a gesture handler for one of my views. Fortunately in my case, I had already done this successfully for a double-tap and was trying to sort the single tap. The code was basically identical but one worked and the other gave me, "unrecognized selector..." at runtime. It was only when I looked VERY carefully that I noticed the working function was passed to @selector as handleDoubleTap: and the other as handleSingleTap. Notice the difference? I didn't for ages but one has a colon after it and the other one doesn't. 

Why does this matter? The colon is implying that the handle function is called handleDoubleTap and TAKES A SINGLE PARAMETER - which it does. If you miss out the colon, it is saying, "call a function named handleSingleTap that takes NO PARAMETERS". In a decent language, this would either fail at compile-time because there is no function with one parameter or it would not require you to tell it how many parameters the function has because the runtime would be looking for a named function THAT TAKES THE PARAMETERS IT REQUIRES - in this case, a single pointer to a UIGestureRecognizer.

Conclusion

These kinds of subtle and hard to understand errors are what make people avoid your language. I'm quite sure that if it was not still used for MacOS and iOS, no-one would choose this language. It is archaic and poorly written and sadly, it seems, has not really improved over time. Perhaps if it was completely different from C, then my mindset would expect a completely unique language like Python or Ruby and I wouldn't be expecting it to work like C (when it doesn't) but the pretence just leads people like me with a lot of C-style experience to completely confused. Java, C# and C++ were all logical extensions to C-style syntax but this stuff is nasty. Hopefully, you will still be productive and one day Apple will consider using a normal language for development, even something as old as C++ (which they don't use for some reason). Otherwise, perhaps one of these cross-platform tools like Xamarin or PhoneGap will remove the need for us to endure Objective-C.
Post a Comment