答案 0 :(得分:4)
正如@ user1118321所述,objc_msgSend
基本上是Objective-C的消息调度的实现。基本上,当您发送[foo bar]
之类的消息时,会调用objc_msgSend
,并且它基本上会执行此操作:
找出foo
类。
将bar
消息(转换为基于字符串的选择器)发送到foo
,并获得一个实现(基本上是一个带foo
的C函数和选择器作为它的前两个参数)。这可以在运行时拦截并以很多粗糙的方式进行操作,这非常酷但也会产生性能成本。此外,选择器操作涉及字符串操作,这会产生自己的性能成本。
从第2步调用实现。
如果你想深入了解objc_msgSend
内部运作的细节,那么这篇文章非常棒:https://www.mikeash.com/pyblog/friday-qa-2012-11-16-lets-build-objc_msgsend.html
无论如何,所有这一切显然不会像直接的C函数调用一样快,但对于大多数情况来说,objc_msgSend
的开销不足以成为主要问题(函数本身)是用一些非常好的核心手工优化汇编程序编写的,并使用了一堆缓存技术,所以它可能非常接近它所能提供的最佳性能。但是,有些情况下objc_msgSend
的性能可能会受到关注,对于这些情况,您可以尝试尽量减少使用Objective-C调用,如@ user1118321所述。或者,如果您可以缩小导致问题的特定Objective-C方法调用,则可以使用称为IMP缓存的技术,通过该技术可以查找一次方法并将其实现保存为C函数指针,然后,您可以根据需要重复调用,将对象和选择器作为前两个参数发送。
例如,如果您有此对象:
@interface Foo: NSObject
- (id)doSomethingWithString:(NSString *)bar;
@end
你可以像IMP
一样得到它:
Foo *foo = ...
SEL selector = @selector(doSomethingWithString:);
IMP imp = [foo methodForSelector:selector];
id (*funcVersion)(Foo *, SEL, NSString *) = (id (*)(Foo *, SEL, NSString *))imp;
您可以将funcVersion
和选择器存储在某处,然后像这样调用它。这样做不会产生objc_msgSend
的费用,因为您将有效地跳过上面列表中的前两个步骤。
id returnValue = funcVersion(foo, selector, @"Baz");
答案 1 :(得分:3)
objc_msgSend
是将选择器转换为地址并在每次调用Objective-C中的方法时跳转到它的函数。它并不表示编程本身很差。但如果它占用了您计划的大部分时间,您可能需要考虑重构代码,这样您就不需要调用这么多方法来完成您的工作了。这样做。如果没有关于您的应用程序的任何更多信息,就无法告诉您如何继续。
我以前打过这个。就我而言,我的应用程序正在调用一个方法来检索NSDictionary
。但事实证明,该词典在整个应用程序的生命周期中都是静态的。每次调用它时,该方法都是从头开始创建的。因此,我不是反复调用创建字典的方法,而是在开始时调用它一次并保存(保留)结果,从而消除将来对方法的所有调用。