There are so many apps out there for the iPhone that are doing some pretty graphics/algorithmically intensive stuff. Most are right on the money when it comes to responsiveness, but some are just woeful!
Perhaps it’s the promises of fame and fortune that seems synonymous with iPhone programming, but many developers new to Objective C are doing straight ports or just writing plain ObjC code until their app ‘works’ then just release it. There seems to be a feeling that if an app is slow, the device just can’t handle it.
I’ve been stepping through the hoops of (relatively) computationally heavy apps at the moment with the creation of a generic physics engine for use in a bunch of 2D based games. Because it was my first app with serious algorithms in it, I didn’t give optimization much thought. And if you believe most ‘Good Software Practice” guidelines, that was a good thing. (optimize last, or you’ll be optimizing things that need no optimization at all.)
But perhaps some thought is necessary. At the beginning, it’s very nice to go down the path of using pure ObjC throughout your code. Let’s face it – it has a nice set of design features that make you feel like you’re on a fluffy cloud rather than the hard stainless steel bench of C. And if you’re particularly sick like me, [you setLovesSquareBrackets:YES]. But of course the nice features of ObjC come at a cost, and the biggest one is the passing of messages. C/C++ programmers often forget that when invoking a method on an object in ObjC, you are actually passing a message to the object which has to be converted into a function call at runtime. Great for flexible, extendable libraries – bad for speed.
So you can either start your development with core components using plain C calls, or you can do what I did and wait until the ‘end’ and use the profiler. The ‘Instruments’ tool in conjunction with remote iPhone SDK debugging is great. You can actually run the app on the device and get statistics about what you’re app is doing and when – without a huge penalty to performance.
Take a typical recording and keep an eye out for the msg_send call, and how much time is spent there. You may actually find that you’ve introduced a dependency lock that’s slowing things down or you may have an update timer that’s just being ridiculous and updating a billion times a second.
But if you find out that a lot of time is spent calling msg_send, all hope is not lost. You can still do some optimizations that help out. For the other things I’ll talk about them later.
In simple cases, you do some of the internal work of ObjC yourself and cut out the middle man (sourced from here):
-naive {
for(i=0; i<50000000; i++)
[obj hello];
}
-optimised {
typedef id (*hello_t)(id, SEL, ...);
hello_t ref = [obj methodFor:@selector(hello)];
for(i=0; i<500000000UL; i++)
ref(obj,@selector(hello));
}
which will work in a lot of cases.
But sometimes, you just have to revert to C. Go back to the profiler and see what’s happening. If there are still a lot of msg_send calls clogging up your execution time, then you’ll have to strip out the offenders and just write C functions. It’s really not that bad..