Take the 2-minute tour ×

I have a animation consisting of 100 images. I want to be able to display the animation through a sequence of frames. For example, instead of displaying the animation from 0:00 seconds to 0:32 seconds, I would rather use Frame 0 to Frame 32. I need to do this because I need a LOT of control over the animation (even the difference of one frame would create the wrong result). I have drawn each frame personally, so I know the image of each frame.

Is there anyway I can do this in Cocoa, using Objective-C? How would I do this? All I have is 100 images and I have no idea how to proceed from here. And also, would this be "laggy" compared to specifying by time?

I would prefer a detailed answer because I couldn't find any resources online and am completely new to this.

Note that I am using OS X, not iOS, so please do not provide iOS-related answers. I'm working with Xcode 3.2.6 on Snow Leopard.

share|improve this question

7 Answers 7

up vote 6 down vote accepted

The way to have the most control would be to store all of your images in an array. If you named your images something like "frame.png" (i.e. "frame1.png") then you can quickly load all of your images like this:

frames = [[NSMutableArray alloc] init]; // In header: NSMutableArray *frames;
for (int i = 1; i < 100; i++) // 100 can be replaced for any number of frames.
    NSString *filename = [NSString stringWithFormat:@"frame%i.png", i];
    [frames addObject:[NSImage imageNamed:filename]];

What this does is creates an array and fills it with NSImages named after your files. The %i is substituted in the string for the current value of i.

Now, you'll need another variable to keep track of the current frame. Something like unsigned int currentFrame;. This can either be incremented every update loop, or set to a specific value, giving you complete control over the frame displayed.

Then, in your render loop, you can render whichever frame is currently stored like this:

[(NSImage *)[frames objectAtIndex:currentFrame - 1] drawAtPoint:animPos fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0f];

where animPos is an NSPoint containing the position you wish to draw at. The - 1 is there in the index so you can refer to your frames starting at 1 rather than 0. This code pulls the image at frame currentFrame and renders it to the screen.

Since you are using an array, also be sure to check currentFrame is never equal to a value greater than the max number of frames, something like: if (currentFrame > 100) currentFrame = 1;. This would cause the animation to loop, since when it gets to the last frame, currentFrame would be set back to the beginning index of the array.

For more information on drawing, you should look at: Cocoa Drawing Guide and NSImage Class Reference. Also, if you need more information on how to update the frame every increment of time, look into NSTimer Class Reference.

share|improve this answer
Where would the render loop code go? What class I mean? Would it be an NSImageView? –  fdh Jun 30 '12 at 0:06
the drawAtPoint: code can go in any class you would like. It doesn't need to be performed inside of an NSImageView, and it can render anywhere in the window, even without views. If you don't have many classes, it might be easiest to leave it in the application delegate. However, if you want to use an NSImageView, you can use [NSImageView setImage:(NSImage *)[frames objectAtIndex:currentFrame - 1]] instead of drawAtPoint and let the view handle rendering, positioning, etc. –  wquist Jun 30 '12 at 0:29
Thank You, it works! –  fdh Jul 4 '12 at 17:43

You can use this code for your frame by frame animation. Hope this will help you.

 // create the view that will execute our animation
 UIImageView* imageListView = [[UIImageView alloc] initWithFrame:self.view.frame];

 // load all the frames of our animation
 imageListView.animationImages = [NSArray arrayWithObjects:    
                             [UIImage imageNamed:@"campFire01.gif"],
                             [UIImage imageNamed:@"campFire02.gif"],
                             [UIImage imageNamed:@"campFire03.gif"],
                             [UIImage imageNamed:@"campFire04.gif"],
                             [UIImage imageNamed:@"campFire05.gif"],
                             [UIImage imageNamed:@"campFire06.gif"],
                             [UIImage imageNamed:@"campFire07.gif"],
                             [UIImage imageNamed:@"campFire08.gif"],
                             [UIImage imageNamed:@"campFire09.gif"],
                             [UIImage imageNamed:@"campFire10.gif"],
                             [UIImage imageNamed:@"campFire11.gif"],
                             [UIImage imageNamed:@"campFire12.gif"],
                             [UIImage imageNamed:@"campFire13.gif"],
                             [UIImage imageNamed:@"campFire14.gif"],
                             [UIImage imageNamed:@"campFire15.gif"],
                             [UIImage imageNamed:@"campFire16.gif"],
                             [UIImage imageNamed:@"campFire17.gif"], 
                              //all your 100 images// , nil];

 // all frames will execute in 1.75 seconds
 imageListView.animationDuration = 1.75;
 // repeat the annimation forever
 imageListView.animationRepeatCount = 0;
 // start animating
 [imageListView startAnimating];
 // add the animation view to the main window 
 [self.view addSubview:imageListView];
share|improve this answer
This only works on iOS, the question is about OS X. –  Rafael Oct 7 '12 at 16:29

You might consider using CADisplayLink. Here's an example on how to use it:

In your initialization method, setup the display link:

CADisplayLink* displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(playAnimation:)];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];    

Then add the method:

- (void)playAnimation:(CADisplayLink*)displayLink
    // Set the right image to display
    self.imageToDisplay = TheRightImageBasedOnYourAnimationSequence

    [self setNeedsDisplay];

And lastly, in the drawRect: method, display the image. The CADisplayLink class has attributes to control the frame duration, etc...

share|improve this answer

To reiterate @wquist's response:-

    [frames addObject:[NSImage imageNamed:filename]];

In the past I have had a number of animations with filenames such as image_00000.png, image_00001.png and to take care of them I used something like this:-

NSString *filename = [NSString stringWithFormat:@"frame%05d.png", i];
share|improve this answer

The slideshow portion of this example code can probably help you.


share|improve this answer

Have you tried subclassing NSAnimation, and having it change the image shown every tick?


First, you create a subclass of NSAnimation. Then, override setCurrentProgress: by calling its superclass implementation, and having it change the view depending on currentValue. See the following guide for more in-depth instructions: https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/AnimationGuide/Articles/TimingAnimations.html#//apple_ref/doc/uid/TP40003581-SW1

share|improve this answer
Could you expand? How would I do this? I've never worked with NSAnimation before. –  fdh Feb 25 '12 at 19:36
Its a fairly simple process, explained clearly in the documentation for NSAnimation. See my edit for more detail. –  Daniel Feb 25 '12 at 22:37
Anyone know why all these answers were downvoted? –  Daniel Mar 2 '12 at 18:36

i made a simple project that you parhaps can use: you can find the project here

i hope this is what you need

share|improve this answer

Your Answer


