开发者

How many Objective-C messages per second are possible on the iPhone 4?

When implementing algorithms and other things while trying to maintain reusability and separation patterns, I regularly get stuck in situations like this:

I communicate back and forth with an delegate while traversing a big graph of objects. My concern is how much all this messaging hurts, or how much I must care about Objective-C messaging overhead.

The alternative is to not separate anything and always put the individual code right into the algorithm like for example this graph traverser. But this would be nasty to maintain later and is not reusable.

So: Just to get an idea of how bad it really is: How m开发者_开发技巧any Objective-C messages can be sent in one second, on an iPhone 4?

Sure I could write a test but I don't want to get it biased by making every message increment a variable.


There's not really a constant number to be had. What if the phone is checking email in the background, or you have a background thread doing IO work?

The approach to take with things like this is, just do the simple thing first. Call delegates as you would, and see if performance is OK.

If it's not, then figure out how to improve things. If messaging is the overhead you could replace it with a plan C function call.


Taking the question implicitly to be "at what point do you sacrifice good design patterns for speed?", I'll add that you can eliminate many of the Objective-C costs while keeping most of the benefits of good design.

Objective-C's dynamic dispatch consults a table of some sort to map Objective-C selectors to the C-level implementations of those methods. It then performs the C function call, or drops back onto one of the backup mechanisms (eg, forwarding targets) and/or ends up throwing an exception if no such call exists. In situations where you've effectively got:

int c = 1000000;
while(c--)
{
    [delegate something];  // one dynamic dispatch per loop iteration
}

(which is ridiculously artificial, but you get the point), you can instead perform:

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
}

What you've done there is taken the dynamic part of the dispatch — the C function lookup — outside the inner loop. So you've lost many dynamic benefits. 'delegate' can't method swizzle during the loop, with the side effect that you've potentially broken key-value observing, and all of the backup mechanisms won't work. But what you've managed to do is pull the dynamic stuff out of the loop.

Since it's ugly and defeats many of the Objective-C mechanisms, I'd consider this bad practice in the general case. The main place I'd recommend it is when you have a tightly constrained class or set of classes hidden somewhere behind the facade pattern (so, you know in advance exactly who will communicate with whom and under what circumstances) and you're able to prove definitively that dynamic dispatch is costing you significantly.

For full details of the inner workings at the C level, see the Objective-C Runtime Reference. You can then cross-check that against the NSObject class reference to see where convenience methods are provided for getting some bits of information (such as the IMP I use in the example).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜