Swift 什么是objc_msgSend?为什么它会占用这么多处理时间?
我一直在分析我基于回合的游戏应用程序,我遇到了一个有趣的(可能)问题。如下图所示,Swift 什么是objc_msgSend?为什么它会占用这么多处理时间?,swift,sprite-kit,Swift,Sprite Kit,我一直在分析我基于回合的游戏应用程序,我遇到了一个有趣的(可能)问题。如下图所示,objc\u msgSend似乎占用了我应用程序运行时间的近一分钟。这是什么?这是一些写得不好的代码的标志吗?谢谢 objc\u msgSend是一个函数,它将选择器转换为地址,并在调用Objective-C中的方法时跳转到该地址。它本身并不表示编程不好。但是,如果它占用了大部分程序的时间,您可能需要考虑重构代码,这样您就不需要调用这么多方法来完成您正在做的工作。如果没有关于你的应用程序的更多信息,就不可能告诉你如
objc\u msgSend
似乎占用了我应用程序运行时间的近一分钟。这是什么?这是一些写得不好的代码的标志吗?谢谢
objc\u msgSend
是一个函数,它将选择器转换为地址,并在调用Objective-C中的方法时跳转到该地址。它本身并不表示编程不好。但是,如果它占用了大部分程序的时间,您可能需要考虑重构代码,这样您就不需要调用这么多方法来完成您正在做的工作。如果没有关于你的应用程序的更多信息,就不可能告诉你如何继续
我以前打过这个。在我的例子中,我的应用程序调用了一个方法来检索
NSDictionary
。但事实证明,在应用程序的整个生命周期中,字典都是静态的。每次我调用它时,该方法都是从头开始创建的。因此,我没有重复调用创建字典的方法,而是在开始时调用了它一次,并保存(保留)了结果,消除了以后对该方法的所有调用。正如@user1118321所说,objc\u msgSend
基本上是Objective-C消息分派的实现。基本上,当您发送诸如[foo bar]
之类的消息时,objc\u msgSend
会被调用,它基本上是这样做的:
foo
bar
消息(转换为基于字符串的选择器)发送到foo
,并获得一个实现(这基本上是一个C函数,将foo
和选择器作为其前两个参数)。这可以在运行时被截获,并以许多粗糙的方式进行操作,这非常酷,但也会带来性能成本。此外,选择器操作还涉及字符串操作,这会导致自身的性能损失objc\u msgSend
的内部工作原理,本文非常棒:
无论如何,所有这些显然不会像直接的C函数调用那么快,但是对于大多数情况,来自objc\u msgSend
的开销不足以成为主要问题(该函数本身是用一些相当核心的手工优化汇编程序编写的,并使用了一系列缓存技术,因此它可能非常接近它所能提供的最佳性能)但是,在某些情况下,objc\u msgSend
的性能可能会成为一个问题,对于这些情况,您可以尽量减少使用Objective-C调用,正如@user1118321所说。或者,如果您可以缩小导致问题的特定Objective-C方法调用的范围,您可以使用一种称为IMP缓存的技术,即y,您可以查找一次方法并将其实现保存为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\u msgSend
的成本,因为您实际上会跳过上面列表中的前两个步骤
id returnValue = funcVersion(foo, selector, @"Baz");
谢谢!我可以问一下,什么样的例子会导致objc\u msgSend。我理解你的例子,但不同类的属性访问也会调用它吗?例子:
self.gameModel!.gameMapModel![Int(self.currenttiletooperation!.y)][Int(self.currenttiletooperation!.x)].tileType=.counter
和:(self.mainBoardMap!.scene as!GameScene).gameCameraAndUI!。显示gamenotification(文本:“计数器不足”,文本颜色:nil,完成:{})
我相信属性也是以类似的方式实现的,尽管我不是肯定的。您可以阅读有关Objective-C运行时的信息。@Aleksandr我用有关运行时的更多信息更新了我的答案。有关详细信息,请参阅。@Aleksandr抱歉,我没有立即注意到您在评论中的其他问题。属性访问也会被取消通过objc_msgSend
,它们基本上是Objective-C2.0中引入的语法糖。在旧的1.0版本中,我们只是通过常规的消息发送符号访问属性,即[self-someProperty]
和[self-setSomeProperty:newValue]
而不是self.someProperty
和self.someProperty=newValue
。这两个符号在引擎盖下的作用仍然相同。