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

Apple's Objective-C Runtime Guide says that you should never use objc_msgSend () in your own code, and we recommend that you use the ForSelector: method instead. However, this does not give any reason for this.

What is the danger of calling objc_msgSend () in your code?

+21
objective-c objective-c-runtime cocoa
Jun 23 '13 at 17:26
source share
3 answers

Reason # 1: Bad style - it's redundant and unreadable.

The compiler automatically generates objc_msgSend() calls (or a variant thereof) when detecting Objective-C message expressions. If you know that the class and selector must be sent at compile time, there is no reason to write

 id obj = objc_msgSend(objc_msgSend([NSObject class], @selector(alloc)), @selector(init)); 

instead

 id obj = [[NSObject alloc] init]; 

Even if you don’t know the class or selector (or even both), it is still safer (at least the compiler has a chance to warn you if you are doing something potentially unpleasant / wrong) to get a correctly printed function pointer to the implementation itself and use this function pointer instead:

 const char *(*fptr)(NSString *, SEL) = [NSString instanceMethodForSelector:@selector(UTF8String)]; const char *cstr = fptr(@"Foo"); 

This is especially true when method argument types are sensitive to default promotions - if they exist, then you do not want to pass them through the objc_msgSend() variable arguments, because your program will quickly call undefined.

Reason # 2: Dangerous and error prone.

Pay attention to the part "or some variant" in # 1. Not all messages are sent using the objc_msgSend() function objc_msgSend() . Due to the complexity and requirements in the ABI (in particular, in the calling function convention), there are separate functions for returning, for example, values ​​or floating point structures. For example, in the case of a method that performs some kind of search (substrings, etc.), and returns an NSRange structure, depending on the platform, it may be necessary to use the function version returning the structure of the message:

 NSRange retval; objc_msgSend_stret(&retval, @"FooBar", @selector(rangeOfString:), @"Bar"); 

And if you make a mistake (for example, you use an inappropriate messenger function, you mix pointers with return value and self , etc.), your program will probably behave incorrectly and / or crash. ( And you are most likely mistaken, because it is not even so simple - not all methods that return a struct use this option, since small structures will fit into one or two processor registers, except for using the stack as the place of the return value. Therefore, if you are not an ABI hardcore hacker, you probably want the compiler to do its job, or there were dragons there.)

+37
Jun 23 '13 at 17:34
source share

You ask, "What are the dangers?" and @ H2CO3 listed some finale with "if you are not a hardcore ABI hacker" ...

As with many rules, there are exceptions (and perhaps a few more with ARC). Therefore, your arguments for using msgSend should go something like this:

[1] I think I should use msgSend - not .

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

...

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

...

[100] Indeed, this looks like a case for msgSend , I see no other solution! OK, read Document.m in Apple's TextEdit sample code . 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 found and understood the exception that proves the correctness and coincidence of your case, use it !

NTN

+10
Jun 23 '13 at 7:10
source share

I can make a case. We use msgSend in one of our C ++ files in a cross-platform project (Windows, Mac, and Linux). We use it to count the links in the backup (shared code), which is later used to switch from the external interface to the server and vice versa. A very special case, really.

+4
Jun 25 '13 at 12:31 on
source share



All Articles