I am working on an app where the customer wants to animate large images (305x332). The customer wants 50 frames in 1.75 seconds to animate in a loop. I am finding that the app is very slow with this much processing. It is slow to start, respond to touches and to shutdown. On the iPhone it self, the app will often crash or lockup the phone. See the code below. My question(s):
- Am I doing something to cause the poor performance or is 50 frames too much to ask?
- Is there a best practices for number of frames in animations and speed of animations?
- Is there a best practices for size of images in an animation?
Please let me know. Here is the code...
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
for(int i = 1; i <= 50; i++)
{
[tempArray addObject:[UIImage imageNamed:[NSString stringWithFormat:@"%@-%d-%04d.JPG",[constitution getConstitutionWord], constitution.getAnimationEnum, i]]];
}
backgroundImage.animationImages = tempArray;
[tempArray release];
backgroundImage.animationDuration = 1.75; // seconds
backgroundImage.animationRepeatCount = 0; // 0 = loops forever
[backgroundImage startAnimating];
The way it was explained to me, the way OS X, including iPhone OS, renders it's view, the images would be continually stacked on each other. Something that you may want to try is a large sprite image that includes all frames, cropped to one at a time and snaps to each frame as needed. This also reduces the image file overhead and rendering speed much like CSS sprites do in web apps. This works well in the HTML5/CSS3 animations I've done on the iPhone and may have the same success in your background image animation.
I ran some tests a while back. Managed to max out around 40 frames of around 20K PNGs before UIImageview animation gave up and borked.
If you need more than that, you can either switch to use video or write your own animation rendering engine. The rendering engine is pretty straightforward. It would run on a timer that fetches an already loaded UIImage from the head of a queue, updates the view then releases the image. A separate thread preloads a few frames ahead at the tail end of the queue. This way, you have at most N frames in memory at any given time. You can tweak it to find the optimum balance between timer delay and number of frames to pre-load for your app.
A project I worked on used that technique to display hundreds of large images with no problems.
A few tips:
Use CALayers as much as you can.
Don't do ANY scaling when displaying each frame. Try to make each source image the exact size you want displayed.
Try not to cover the animation with other views. It'll slow things down.
You can load the image list from the bundle or by scanning a directory. The disadvantage of bundle is that the images can't be updated without updating the whole app. The disadvantage of loading from a directory is that on first startup you'll have to copy the images from the bundle to a writable location and your app size at runtime gets larger. The main benefit is that you can update the media in that directory via the net.
Sound synchronization becomes a bit dicey. You'll have to come up with your own way to designate when to start/stop sounds. If you have sound and need it to be precise (like lip-synching) going the video route might be more practical.
Good luck.
I think this is a little too much to ask of the iPhone. Decompressed your images take up about 21Mb according to my fag packet. This will likely cause your app to be terminated on the phone just through memory usage. Shifting that much data into the framebuffer is also going to cause the phone problems.
I think you need to use a more suitable animaton technology. ~30fps at 305*322 sounds like video to me. Video is compressed in such a way that you don't need to hold all of the decompressed frames in memory at once. Sadly, if you want to display video without giving over the whole screen to the built in control, you are going to have to build your own player - VLC has been ported to iPhone so could make a good starting point.