views:

109

answers:

3

Hi there, I am working on an iPhone app at the moment and I am struggling with some animation.

Basically I have 109 frames for dragging about a man on screen, so what I am doing is listening for touches, and calculating which frames I need to switch to.

This works all well and good, but after a while I get a memory leak and the app crashes. I am loading all the images into and Array at startup, and using a UIImageView to display the images. Images are loaded using imageWithContentsOfFile.

What is the best way for me to do this??

Heres some of the source code:

- (void)viewWillAppear:(BOOL)animated {
animationQueue = [[NSMutableArray alloc] initWithObjects:0];
imageArray = [[NSMutableArray alloc] initWithObjects:nil];
for(int i = 1;i<110;i++)
{
    [imageArray addObject:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:[NSString stringWithFormat: @"%i", i] ofType:@"png"]]];
}
[super viewWillAppear:animated];}

View Did Load code:

- (void)viewDidLoad {
animation = [[UIImageView alloc] initWithFrame: CGRectMake(0, 0, 480, 320)];
animation.contentMode = UIViewContentModeCenter;
[self.view addSubview:animation];
animation.image = [imageArray objectAtIndex:40];
[super viewDidLoad];}

Touches Handler:

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {  
// Enumerates through all touch objects
for (UITouch *touch in touches) {
    CGPoint touch_point = [touch locationInView:self.view];
    // calculate which frame to end on
    int pos = ceil((touch_point.x/480) * 108);
    [self redrawAnimation:pos];
}}

Redrawing Animation:

- (void)redrawAnimation:(int)end_frame {
    animation.image = [imageArray objectAtIndex:end_frame];
}

The application crashes when you have been sliding your finger along the screen a few times.

Thanks in advance!

Matt

A: 

Could it be, that your position int sometimes has a value, for which there's no index in the array?

I mean this lines:

int pos = ceil((touch_point.x/480) * 108);
[self redrawAnimation:pos];

What's the error message of the debugger, if the app crashes?

schaechtele
A: 

Isn't it a problem with allocating too much memory? 110 images might take too much of it. How about a change in:

- (void)redrawAnimation:(int)end_frame {
  animation.image = [imageArray objectAtIndex:end_frame];
}

to:

- (void)redrawAnimation:(int)end_frame {
  animation.image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle]
                                     pathForResource:[NSString stringWithFormat: @"%i", end_frame]
                                              ofType:@"png"]]];
}

and do not preallocate images in -(void)viewWillAppear:(BOOL)animated.

I know, it would be much slower, but if it's a case of memory limit you rather have no other choice. You can also try to preallocate only a part of a sequence, but finally the buffer might be starved if you animate images faster than they would be loaded.

Daniel Bauke
Thanks! Works a lot better without preloading the images, and still has the desired effect.
A: 

You don't say what the actual crash is, which may be an important clue. But I'm willing to guess, depending on the size of your bitmaps, that you're just holding too much in memory.

UIImage is generally pretty smart behind the scenes. E.g. in your viewWillAppear, although you're creating 110 image references, it's probably not loading the files until needed. When you move your finger around a bunch, do you think that that's what it takes to actually invoke/load all the frames? It could be that you're hitting a limit somewhere on the way to that? UIImage is also known to smartly flush bitmap data in low memory situations, but it's a bit of a black box to the caller.

Figure out exactly where the app crashes. Also consider running Instruments to profile memory usage and whatnot. It could be something not memory related at all (a bug somewhere else in your code?). Or try using half or a quarter as many images, etc, to see what happens.

If it turns out to be resource management, you'll have finer grained control if you either manage the memory explicitly by creating and releasing UIImages on the fly (or in some windowed/batched preload fashion) or check out Cocos2D or even raw OpenGL for proper sprites/textures, where the control over this stuff is much more accessible (at the cost of a lot more plumbing.)

quixoto