Reputation: 53
I am creating an application for the iPhone which involves having more than one button which all animate the same UIImageView. It works well in the simulator, (like practically all apps) but when it comes to the device it plays the animation well, but with repetitive pressing of the buttons the app quits. So far I have implemented 2 buttons. Here's what happens when they are pressed. Okay, I have 44 MB of ram available when my app starts, Then when I press the first of 2 buttons that start an animation the available memory goes down to 31 and climbs up to 32, then when I press the second button the available memory goes down to 9 then climbs to 24 and then strangely declines to 10 slowly. If the first button is then pressed then the available memory climbs to 14MB And under repetitive pressing of these buttons the apps memory goes down to 4 to 3 MB and quits. In instruments there are no leaks. Here is my code incase anyone can spot where my memory issue lurks. (BTW, I'm still developing on 2.2.1 because if I upgrade to 3.0 i won't be able to test my apps on the device as I am not enrolled in the apple developer program yet and I followed an online tutorial to get apps onto the device that only works with 2.2.1)
@synthesize 123pig;
- (IBAction)startClick:(id)sender{
animationTimer = [NSTimer scheduledTimerWithTimeInterval:(1.00/30.00) target:self selector:@selector(tick) userInfo:nil repeats:NO];
123pig.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed: @"123pigapple0001.png"],
[UIImage imageNamed: @"123pigapple0002.png"],
[UIImage imageNamed: @"123pigapple0003.png"],
[UIImage imageNamed: @"123pigapple0004.png"],
[UIImage imageNamed: @"123pigapple0005.png"],
[UIImage imageNamed: @"123pigapple0006.png"],
[UIImage imageNamed: @"123pigapple0007.png"],
[UIImage imageNamed: @"123pigapple0008.png"],
[UIImage imageNamed: @"123pigapple0009.png"],
[UIImage imageNamed: @"123pigapple0010.png"],
[UIImage imageNamed: @"123pigapple0011.png"],
[UIImage imageNamed: @"123pigapple0013.png"],
[UIImage imageNamed: @"123pigapple0014.png"],
[UIImage imageNamed: @"123pigapple0015.png"],
[UIImage imageNamed: @"123pigapple0016.png"],
[UIImage imageNamed: @"123pigapple0017.png"],
[UIImage imageNamed: @"123pigapple0018.png"],
[UIImage imageNamed: @"123pigapple0019.png"],
[UIImage imageNamed: @"123pigapple0020.png"],nil];
[123pig setAnimationRepeatCount:1];
123pig.animationDuration =.7;
[123pig startAnimating];
}
- (void)tick{
[self animatePig];
}
- (void)animatePig{
UIImage *pigImage13=[UIImage imageNamed:@"123pigapple0020.png"];
if(123pig.image == pigImage13)
123pig.image = pigImage13;
else
123pig.image = pigImage13;
}
- (IBAction)startClick1:(id)sender{
animationTimer1 = [NSTimer scheduledTimerWithTimeInterval:(1.00/30.00) target:self selector:@selector(tick1) userInfo:nil repeats:NO];
123pig.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed: @"123pig0015.png"],
[UIImage imageNamed: @"123pig0016.png"],
[UIImage imageNamed: @"123pig0017.png"],
[UIImage imageNamed: @"123pig0018.png"],
[UIImage imageNamed: @"123pig0019.png"],
[UIImage imageNamed: @"123pig0020.png"],
[UIImage imageNamed: @"123pig0021.png"],
[UIImage imageNamed: @"123pig0022.png"],
[UIImage imageNamed: @"123pig0023.png"],
[UIImage imageNamed: @"123pig0024.png"],
[UIImage imageNamed: @"123pig0025.png"],
[UIImage imageNamed: @"123pig0026.png"],
[UIImage imageNamed: @"123pig0027.png"],
[UIImage imageNamed: @"123pig0028.png"],
[UIImage imageNamed: @"123pig0029.png"],
[UIImage imageNamed: @"123pig0030.png"],
[UIImage imageNamed: @"123pig0031.png"],
[UIImage imageNamed: @"123pig0032.png"],
[UIImage imageNamed: @"123pig0033.png"],
[UIImage imageNamed: @"123pig0034.png"],
[UIImage imageNamed: @"123pig0035.png"],
[UIImage imageNamed: @"123pig0036.png"],
[UIImage imageNamed: @"123pig0037.png"],
[UIImage imageNamed: @"123pig0038.png"],
[UIImage imageNamed: @"123pig0039.png"],
[UIImage imageNamed: @"123pig0040.png"],
[UIImage imageNamed: @"123pig0041.png"],
[UIImage imageNamed: @"123pig0042.png"],
[UIImage imageNamed: @"123pig0043.png"],
[UIImage imageNamed: @"123pig0044.png"],
[UIImage imageNamed: @"123pig0045.png"],
[UIImage imageNamed: @"123pig0046.png"],
[UIImage imageNamed: @"123pig0047.png"],
[UIImage imageNamed: @"123pig0048.png"],
nil];
[123pig setAnimationRepeatCount:1];
123pig.animationDuration =2.7;
[123pig startAnimating];
}
- (void)tick1{
[self animatePig1];
}
- (void) animatePig1{
UIImage *pigImage11=[UIImage imageNamed:@"123pig0048.png"];
if(123pig.image == pigImage11)
123pig.image = pigImage11;
else
123pig.image = pigImage11;
}
- (void)stopTimer
{
[animationTimer invalidate];
[animationTimer release];
[animationTimer1 invalidate];
[animationTimer1 release];
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
123pig.center = location;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)dealloc {
[super dealloc];
[123pig release];
}
@end
I have an idea that it's imageNamed thats causing it and that 2.2.1 doesn't clear it's cache even after a memory warning, and on another SO question someone said "My understanding is that the +imageNamed: cache should respect memory warnings on iPhone OS 3.0. Test it when you get a chance and report bugs if you find that this is not the case." Now even if i did download the firmware and SDK of 3.0 I wouldn't know if it was clearing the cache of imageNamed because I wouldn't be able to test it on a device! BTW when answering keep in mind that I am new to The iPhone sdk. Thanks in advance.
----------------Edit---------------- I've just been accepted into the apple iphone developer program. WOOOHOOO, I'll check if 3.0 releases cached images properly.
-------------Edit------------------ Yes it does release cached images. Check my answer below for further clarification.
Upvotes: 1
Views: 4124
Reputation: 53
Okay people, It would seem that iPhone OS 3.0 does clear cached images on a did receive memory warning command, wooohooo! Me 1, Xcode 0. A bit more detail: In the iPhone os 2.2.1 when you release an animated Image view, the cached images aren't released, so if your app had loads of animations then eventually the iPhone would run out of memory and quit. So you would just have to go into other more complex methods of animation, and no one wants to do that if they can avoid it. But now releasing does clear the cache! I can tell because when I press a button in my app to animate a view there's a bit of a wait until the animation plays, then if that is pressed again there is no wait (because it cached it) But then if you press another button that animates that view, the previous cached animation is released! So pressing the first button gives you that original wait, so I can relax now and get on with developing rather then trying to fix a memory management issue that boils down to be apples fault.
Upvotes: 1
Reputation: 28600
Your dealloc code is incorrect. You should only be releasing 123pig, not deallocating it. You should do so before calling [super dealloc]
since after that call, all your instance variables (incling 123pig) may be invalidated. This may have manifested itself as not releasing the image memory since there is a dangling reference to 123pig.
Upvotes: 0
Reputation: 14894
I'm really confused about the behavior of your timers. You start the pig UIImageView animating, and then 1/30th of a second later, your timer fires and it sets the pig image to something else?
You may want to consolidate these two methods of animation (UIImageView animationImages and manual animation using timer). UIImageView really isn't meant to play long animations (see this question). I think it preloads all the images at once when you start the animation - thus the huge memory hit.
A better bet might be to use a timer for everything and keep a local variable corresponding to the current frame. When your timer fires, you could load just one image using imageNamed: and apply it to the UIImageView. I'm not sure what the caching behavior of UIImage is, but I'm pretty sure piling 100 of them into a UIImageView is a bad idea.
Is there any chance you could reduce the frame rate of your animation as well? It seems you're trying to flip through all 100 images in the pig's animation in 2.7 seconds - that's 37 fps! 24 fps would probably be fine and help lower your memory footprint.
Also - this is off topic, but I noticed you're calling [123pig dealloc] in your dealloc function. In general, you should just call release, and dealloc will be called automatically if the object's retain count is zero (meaning the object is no longer used). Manually calling it could cause you to destroy things that another object in the app is still using. Probably doesn't matter in this case, but it could cause some nasty bugs in other scenarios.
Sorry I don't have a definite answer on the cache issue. Hope that helps a bit!
Upvotes: 0