在尝试维护可重用性和分离模式的同时实现算法和其他事情时,我经常陷入这样的情况:
在遍历大型物体图时,我与代表来回沟通。我担心的是所有这些消息都会受到多大伤害,或者我必须关心Objective-C消息传递的开销。
另一种方法是不分离任何内容,并始终将单个代码放入算法中,例如此图遍历器。但是这样做会很难维持,而且不可重复使用。
所以:只是想知道它到底有多糟糕:在iPhone 4上可以在一秒钟内发送多少个Objective-C消息?
当然,我可以编写一个测试,但我不希望通过使每个消息增加一个变量来使它变得有偏见。
答案 0 :(得分:4)
实际上没有一个恒定的数字。如果手机在后台检查电子邮件,或者您有后台线程在进行IO工作,该怎么办?
采取这样的方法的方法是,先做一件简单的事情。像你一样呼叫代表,看看性能是否正常。
如果不是,那么弄清楚如何改进。如果消息传递是开销,则可以用计划C函数调用替换它。
答案 1 :(得分:3)
隐含地提出问题是“你在什么时候牺牲了良好的设计模式以获得速度?”,我将补充说,你可以在保持大多数的同时消除许多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)。