在实施算法和其他方法同时尝试保持可重用性和分离模式时,我经常陷入如下情况:
在遍历大对象图时,我与代表来回交流。我担心的是,所有这些消息传递都会受到多大的伤害,或者我必须在多大程度上关心Objective-C消息传递的开销。
另一种选择是不分离任何内容,并始终将单个代码正确地放入算法中,例如此图形遍历器。但这以后再维护很讨厌,并且不可重用。
所以:只是想知道它到底有多糟糕:在一台iPhone 4上在一秒钟内可以发送多少个Objective-C消息?
当然,我可以编写一个测试,但是我不想通过使每个消息递增一个变量来使它有偏见。
最佳答案
隐含地认为问题是“您在什么时候牺牲了良好的设计模式以提高速度?”,我将补充说,您可以消除许多Objective-C成本,同时又保留了良好设计的大多数优点。
Objective-C的动态调度会参考某种表,以将Objective-C选择器映射到这些方法的C级实现。然后,它执行C函数调用,或放回备用机制之一(例如,转发目标)上,并且/或者如果不存在这样的调用,则最终引发异常。在有效的情况下:
int c = 1000000;
while(c--)
{
[delegate something]; // one dynamic dispatch per loop iteration
}
(这是可笑的,但是您明白了这一点),您可以改为执行:
int c = 1000000;
IMP methodToCall = [delegate methodForSelector:@selector(something)];
while(c--)
{
methodToCall(delegate, @selector(something));
// one C function call per loop iteration, and
// delegate probably doesn't know the difference
}
您在此处所做的事情是在内循环外部进行了调度的动态部分-C函数查找。因此,您失去了许多动态的好处。 'delegate'不能在循环中陷入混乱,其副作用是您可能破坏了键值观察,并且所有备份机制都无法正常工作。但是,您设法做到的是将动态内容从循环中拉出来。
由于它很丑陋并且破坏了许多Objective-C机制,因此在一般情况下,我会认为这种做法不好。我推荐的主要地方是当您在外观模式下的某个地方隐藏了一个紧密受限的类或类集时(因此,您事先知道确切的人将在什么情况下与谁进行交流),并且能够最终证明动态调度会极大地花费您。
有关C级内部工作的完整详细信息,请参见Objective-C Runtime Reference。然后,您可以对照NSObject class reference进行交叉检查,以查看在何处提供了一些便捷方法来获取一些信息(例如本例中使用的IMP)。