I am currently creating my first iPhone app in Objective C and getting a lot of warnings because I've in many places taken advantage of the fact that Objective C is a dynamically typed language. I get a lot of 'class' may not respond to '-message:' warnings. Should I strive to remove all these warnings? If yes, then what's the benefit of having a dynamic language at your disposal?
3 Answers
I can't really answer the question about Objective-C being really dynamic or not. I think it stays in the middle of dynamic and static world.
However, keeping warnings is rarely a good practice, as real warnings you are interested in are lost in the middle of a lot of warnings you don't care about.
So, you should get rid of these warnings. There are several things you can do :
- disable the "may not respond to" warnings (but you may lost real warnings)
- use protocols ( quite static way )
- use optional declarations in protocols ( a bit "more dynamic" ).
- use optional declarations in categories for NSObject for example ( even "more dynamic" )
- use "performSelector" method, which explicitly tells you, the reader of your code, and the compiler that you are calling "dynamic" method"
- use id "type" wherever an instance should be used in a non static way
Disclaimer : I don't say all of these points are good practices, but they are technical ways of achieving the goal of getting rid of warnings
I get a lot of 'class' may not respond to '-message:' warnings. Should I strive to remove all these warnings?
Yes, get rid of the warnings. If you're sending a message to an object, then you must be pretty confident that the object does, in fact, have a method by that name. Why not let the compiler know that as well? Mostly, this just means using appropriate types for your object pointers.
Say you have a pointer of type UIView*
, but you know that any object that the pointer will ever point to will be an instance of UIControl
, so it's safe to send a message like -allTargets
. That'll work just fine, but the compiler will warn that UIView
may not respond to -allTargets
. The simple solution is to change the pointer type to UIControl*
, since you know that will always be the case anyway.
Another situation is where you have several objects of different types that all happen to implement methods with the same name. In that case, changing the pointer type doesn't seem such a great option because you don't know what type of object you might be dealing with; you only know that any object you deal with supports the message your sending. In that case, declare a protocol containing whatever method or methods you're sending, and declare the pointer as a pointer to an object implementing that protocol, like:
UIView<MyProtocol> *myPointer;
In both cases above, you don't lose any dynamism by fixing the warning. You're just sharing with the compiler your knowledge of the restrictions that already exist. You're also making your code more explicit, which makes it easier to maintain.
Most important, by eliminating these easy-to-fix warnings, you'll make it easier to spot other warnings that might alert you to a more significant problem.
If yes, then what's the benefit of having a dynamic language at your disposal?
'Dynamic' here really just means that the ability of an object to respond to a message isn't known until run time. If you were writing in, say, C++, you'd get an error instead of a warning during compilation because the compiler would know for certain that class X does not implement method Y. In Objective-C, you still have to make sure that objects can respond to the messages you send them, but the error you get if you fail in that regard doesn't come until you run the program.
The Objective-C compiler automatically inserts casts into the binary code where the arguments and return types are of different types (e.g. different size integers). If the compiler can't unambiguously figure out the signature of the method you're using at compile time, it's possible it can get this wrong leading to very weird bugs.
(This is why the compiler also has special warning messages for "no method found" and "multiple methods found", since in those cases it's even more likely to get it wrong)