通过Apache Cordova的源代码,我遇到了两行令我困惑的代码:
//[obj performSelector:normalSelector withObject:command];
objc_msgSend(obj,normalSelector,command);
从Apple的文档来看,这两种方法之间似乎没有太大区别。
id objc_msgSend(id theReceiver,SEL theSelector,...) 将带有简单返回值的消息发送到类的实例。
- (id)performSelector:(SEL)aSelectorwithObject:(id)anObject 以对象作为参数向接收方发送消息。 (所需的)
这两种方法之间究竟有什么区别?在上面的例子中,两者都发送带有对象作为参数的消息给接收对象。
答案 0 :(得分:13)
你问两个“方法”之间的区别,但其中只有一个实际上是一种方法。 objc_msgSend
函数是一个函数。不是一种方法。
当您在Objective C中的任何对象上调用任何方法时,objc_msgSend
函数是实际调用的函数。例如,以下两个基本等效:
// This is what the compiler generates
objc_msgSend(obj, @selector(sel:), param);
// This is what you write
[obj sel:param];
// You can check the assembly output, they are *almost* identical!
这里的主要区别是objc_msgSend
没有被编译器检查类型 - 或者至少,它的参数不会根据选择器的参数类型进行类型检查。所以以下大致相同:
[obj performSelector:normalSelector withObject:command];
objc_msgSend(obj, @selector(performSelector:withObject:),
normalSelector, command);
但是,这有点浪费,因为所有performSelector:withObject:
都会调用objc_msgSend
。
HOWEVER:您应该远离obc_msgSend
,因为它不是类型安全的,如上所述。所有apache开发人员正在做的是删除一个方法调用,这在大多数情况下只会给你非常轻微的性能优势。
答案 1 :(得分:7)
注释掉的行是正确的,objc_msgSend()
行不正确,因为它需要显式输入(有时候varargs与某些平台上的非varargs函数调用不兼容)。
他们有效地做同样的事情。实际上,方法调用版本只是objc_msgSend()
的包装。