Reputation: 1691
I am having a memory problem. I may not understand how popping the current UIViewcontroller from the navigationcontroller works. But I would think that it would release it's memory, atleast when it's running low. Like call the dealloc method. I have a class that inherits from UIViewController. I am basically doing an png animation sequence. I can't use animationImages because I need some cross fade. Anyways, when I watch the Activity Monitor and I open the page (watch the memory rise by 30MBs) then I pop it. The memory goes down by a few MBs but not by the full amount. So this keeps happening until the app crashes. The Leak detector doesn't show any leaked objects. I think I am taking care of it. I can paste my code if that would help. Is there something I don't understand about NavigationController and releasing UIViewControllers?
Here is the code:
-(void)addImage:(NSString*)imageName{
if (!images){
images = [[NSMutableArray alloc] init];
}
// UIImage*image = [[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:[imageName stringByReplacingOccurrencesOfString:@".png" withString:@""] ofType:@"png"]];
[images addObject:imageName];
// [image release];
}
-(UIImage*)getImage:(NSString*)imageName{
return [UIImage imageNamed:imageName];
}
// left pad the image number with 0
-(NSString*)formatImageName:(int)num andName:(NSString*)imgName{
NSString* imgNum = [NSString stringWithFormat:@"%i",num];
if (num < 10){
imgNum = [NSString stringWithFormat:@"0%i",num];
}
return [NSString stringWithFormat:imgName,imgNum];
}
// Returns a UIImageView that contains the next image to display
- (UIImageView *)nextImageView
{
if(runOnce && hasRunOnce && pictureIndex == 0){
return nil;
}
// get the image at the next index
UIImage *image = [self getImage:[images objectAtIndex:pictureIndex]];
++pictureIndex; // increment the index
// create an image view for the image
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
//[image release];
// resize the image to fill the screen without distorting
imageView.frame = rotator.frame;
imageView.autoresizesSubviews = NO;
[imageView setContentMode:UIViewContentModeCenter];
// Makes the image move proportionally in any direction if the
// bounds of the superview change when the iPhone is rotated.
imageView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleTopMargin |
UIViewAutoresizingFlexibleBottomMargin);
if(pictureIndex > images.count -1){
pictureIndex = 0;
}
hasRunOnce = YES;
return imageView;
}
- (void)timerFired:(NSTimer *)_timer{
nextImageView = [self nextImageView];
if(nextImageView){
[self.view addSubview:nextImageView];
nextImageView.alpha = 0.0;
//NSLog(@"timerFired - image no: %i", pictureIndex);
// begin animation block
[UIView beginAnimations:nil context:nextImageView];
[UIView setAnimationDuration:animationDuration]; // set the animation length
[UIView setAnimationDelegate:self]; // set the animation delegate
// call the given method when the animation ends
[UIView setAnimationDidStopSelector:@selector(transitionFinished:finished:context:)];
// make the next image appear with the chosen effect
[nextImageView setAlpha:1.0]; // fade in the next image
[currentImageView setAlpha:0.0]; // fade out the old image
[UIView commitAnimations];
} else {
[timer invalidate];
timer = nil;
}
}
// called when the image transition animation finishes
- (void)transitionFinished:(NSString *)animationId finished:(BOOL)finished context:(void *)context
{
[currentImageView removeFromSuperview]; // remove the old image
currentImageView.image = nil;
[currentImageView release]; // release the memory for the old image
currentImageView = context; // assign the new image
}
-(void)startRotator{
pictureIndex = 0; // reset the index
currentImageView = [self nextImageView]; // load the first image
[self.view addSubview:currentImageView]; // add the image to the view
timer = [NSTimer scheduledTimerWithTimeInterval:scheduledInterval
target:self
selector:@selector(timerFired:)
userInfo:nil
repeats:YES];
}
-(void)stopRotator{
NSLog(@"ImageRotator - StopRotator Called");
[timer invalidate];
timer = nil; // set timer to nil
[currentImageView removeFromSuperview]; // remove the current image
currentImageView.image = nil;
[currentImageView release];
currentImageView = nil;
if(nextImageView){
[nextImageView removeFromSuperview]; // remove the current image
nextImageView.image = nil;
//[nextImageView release];
nextImageView = nil;
}
}
// called after this controller's view was dismissed, covered or otherwise hidden
- (void)viewWillDisappear:(BOOL)animated
{
[self stopRotator];
[images release];
images = nil;
[super viewWillDisappear:animated];
}
Upvotes: 0
Views: 622
Reputation: 1691
The memory problem ended up being the ImageNamed method. Once I used the other method overrode it with the following, everything seemed to work fine.
@implementation UIImage(imageNamed_Hack)
+ (UIImage *)imageNamed:(NSString *)name {
return [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:name ofType:nil]];
}
@end
Upvotes: 0
Reputation: 8383
The first thing that I think you should change is the code below
- (void)timerFired:(NSTimer *)_timer
{
// all your code
.......
.......
//add these two lines at bottom
[nextImageView release];
//I think the leak is because you are adding imageViews and not releasing it .... when ever you add any subview to any view its retain count is incleased.
currentImageView.image = nil;
//also you are not using current view any more because you are setting its alfa to 0 so you can set its image to nil.
}
Upvotes: 0
Reputation: 8383
first of all there is an abrupt increase in memory because you are storing all that images in your array, for that I would suggest you to store them in document directory and address of all those in array (array of stings). Also one idea to decrease the memory use would be to use
myImageView.image = nil;
if you are using any imageView to display image, use above line whenever you are not displaying any image. One thing to mind is that when the application go out of memory then it calls
- (void)didReceiveMemoryWarning {
}
not
- (void)dealloc {
}
I would suggest you to read memory management
Also you can use Instruments
to check for memory leaks
Upvotes: 1