Reason #1: Bad style - it's redundant and unreadable.
The compiler automatically generates calls to objc_msgSend()
(or some variant thereof) when it encounters Objective-C messaging expressions. If you know the class and the selector to be sent at compile-time, there's no reason to write
id obj = objc_msgSend(objc_msgSend([NSObject class], @selector(alloc)), @selector(init));
instead of
id obj = [[NSObject alloc] init];
Even if you don't know the class or the selector (or even both), it's still safer (at least the compiler has a chance to warn you if you are doing something potentially nasty/wrong) to obtain a correctly typed function pointer to the implementation itself and use that function pointer instead:
const char *(*fptr)(NSString *, SEL) = [NSString instanceMethodForSelector:@selector(UTF8String)];
const char *cstr = fptr(@"Foo");
This is especially true when the types of the arguments of a method are sensitive to default promotions - if they are, then you don't want to pass them through the variadic arguments objc_msgSend()
takes, because your program will quickly invoke undefined behavior.
Reason #2: dangerous and error-prone.
Notice the "or some variant thereof" part in #1. Not all message sends use the objc_msgSend()
function itself. Due to complications and requirements in the ABI (in the calling convention of functions, in particular), there are separate functions for returning, for example, floating-point values or structures. For example, in the case of a method that performs some sort of searching (substrings, etc.), and it returns an NSRange
structure, depending on the platform, it may be necessary to use the structure-returning version of the messenger function:
NSRange retval;
objc_msgSend_stret(&retval, @"FooBar", @selector(rangeOfString:), @"Bar");
And if you get this wrong (e. g. you use the inappropriate messenger function, you mix up the pointers to the return value and to self
, etc.), your program will likely behave incorrectly and/or crash. (And you will most probably get it wrong, because it's not even that simple - not all methods returning a struct
use this variant, since small structures will fit into one or two processor registers, eliminating the need for using the stack as the place of the return value. That's why - unless you are a hardcore ABI hacker - you rather want to let the compiler do its job, or there be dragons.)