Why shouldn't you use objc_msgSend() in Objective C?

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.)


You ask "what are the dangers?" and @H2CO3 has listed some ending with "unless you are a hardcore ABI hacker"...

As with many rules there are exceptions (and possibly a few more under ARC). So your reasoning for using msgSend should go something along the lines of:

[ 1] I think I should use msgSend - don't.

[2] But I've a case here... - you probably haven't, keep looking for another solution.

...

[10] I really think I should use it here - think again.

...

[100] Really, this looks like a case for msgSend, I can't see any other solution! OK, go read Document.m in the TextEdit code sample from Apple. Do you know why they used msgSend? Are you sure... think again...

...

[1000] I understand why Apple used it, and my case is similar... You've found and understood the exception that proves the rule and your case matches, use it!

HTH


I can make a case. We used msgSend in one of our C++ files (before we switched to ARC) that's in a cross-platform project (Windows, Mac and Linux). We use it to ref count a reference in the backed (the shared code) that's used later to go from frontend to backend and vice versa. Very special case, admittedly.