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

cfischer picture cfischer · Jun 23, 2013 · Viewed 15.7k times · Source

The Objective C Runtime Guide from Apple, states that you should never use objc_msgSend() in your own code, and recommends using methodForSelector: instead. However, it doesn't provide any reason for this.

What are the dangers of calling objc_msgSend() in your code?

Answer

user529758 picture user529758 · Jun 23, 2013

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