khalid soofi
khalid soofi

Reputation: 181

How to make sure that UIImageView's setImage has completed before the next frame

I have some code that continuously generates UIImage frames for animation. Currently I am using a mutable array to save these image objects which can be animated using UIImageView animation methods. Something like following:

NSMutableArray *myFrames...;
while ( number of frames required ) {
    create UIImage frame_xx;
    [myFrames addObject:frame_xx];
}
myUImageView.animationImages = myFrames;
myUImageView.animationDuration = time_length_for_animation;
[myUImageView startAnimating];

The above code works fine, however my problem is that as my animation gets longer then few hundred frames, I start getting memory warnings and eventually the program crashes.

What I would ideally like to do is to display each frame immediately rather then generating a bunch of frames for animation. Animation may be a bit slower this way but I will not be limited to the memory. As soon as the frame_xx is displayed I no longer care for that frame and want to display the next frame.

I have tried using following and they don't work:

[myUImageView setImage:frame_xx] // This only displays the last frame generated in the loop

I have also tried creating a new thread:

        [NSThread detachNewThreadSelector: @selector(displayImage) toTarget:myUImageView withObject:frame_xx]; // again this only shows the last frame generated in the loop

So I am looking for help.. how do you display an image frame immediately in UIImageView, sort of like "flush" right after [myUImageView setImage:frame_xxx]

Any help on this will be greatly appreciated..

KAS

Upvotes: 1

Views: 1184

Answers (2)

Rob Napier
Rob Napier

Reputation: 299565

Have you tried an NSTimer? There are more accurate ways to manage timing, but this should work for basic needs if your frame rate is fairly low. In this example, I'm using 10fps. (I haven't compiled this code.)

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(nextFrame:) userInfo:nil repeats:YES];

...

- (void)nextFrame:(NSTimer*)timer {
    UIImage *image = ... generate image ...
    [self.imageView setImage:image];
}

The underlying problem in your current design is that you must allow the runloop to complete if you want the image to be drawn. You cannot and should not cause drawing to happen in the middle of an event loop.

Upvotes: 2

Josh
Josh

Reputation: 676

Have you tried not using UIImageView and drawing your images in a drawRect: method?

Something like:

    [image drawInRect:rect]; // where 'rect' is the frame for the image

Also, never do any UI drawing in a separate thread. You'll suffer random and persistent crashes from doing so. NSThread#detachNewThreadSelector is not a preferred way to perform multithreaded tasks on iOS. Look at NSOperation and NSOperationQueue. Then when you need to draw to the UI user the NSObject's instance method performSelectorOnMainThread:.

Upvotes: 0

Related Questions