【问题标题】:Memory Release issue - NSArray of UIImages内存释放问题 - UIImages 的 NSArray
【发布时间】:2011-07-14 18:57:11
【问题描述】:

我有记忆问题。我可能不明白从导航控制器弹出当前 UIViewcontroller 的工作原理。但我认为它会释放它的内存,至少在内存不足的时候。就像调用 dealloc 方法一样。我有一个继承自 UIViewController 的类。我基本上是在做一个 png 动画序列。我不能使用动画图像,因为我需要一些交叉淡入淡出。无论如何,当我观看活动监视器并打开页面(观看内存增加 30MB)时,我会弹出它。内存下降了几 MB,但不是全部下降。所以这种情况一直发生,直到应用程序崩溃。泄漏检测器不显示任何泄漏的物体。我想我正在照顾它。如果有帮助,我可以粘贴我的代码。关于 NavigationController 和发布 UIViewControllers 有什么我不了解的地方吗?

代码如下:

-(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];
}

【问题讨论】:

  • 请发布您的代码,以便每个人都可以了解更多关于您的问题

标签: iphone memory memory-management uiviewcontroller uiimage


【解决方案1】:

首先,内存突然增加,因为您将所有图像存储在数组中,为此我建议您将它们存储在文档目录和数组中所有图像的地址(stings 数组)中。 减少内存使用的一种方法是使用

myImageView.image = nil;

如果您正在使用任何 imageView 来显示图像,请在不显示任何图像时使用上面的行。 要记住的一件事是,当应用程序内存不足时,它会调用

- (void)didReceiveMemoryWarning { 
}

不是

- (void)dealloc {
}

我建议你阅读内存管理

您也可以使用Instruments 来检查内存泄漏

【讨论】:

  • 什么时候调用 myImageView.image = nil?当您尝试释放 imageView 时?我还以为我读到了,当你释放 UIImageView 时,底层的图像也被释放了。
  • @smcrdc:尝试使用 Instruments 找出存在内存泄漏的特定位置。这可能会帮助您更准确地了解您需要清理哪些东西。希望这会有所帮助
  • 这就是问题所在,Instruments 显示有任何泄漏。但我可以直观地看到有。
【解决方案2】:

我认为您应该更改的第一件事是下面的代码

- (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.

}

【讨论】:

  • 当您可以编辑同一个答案并将附加信息放入同一个答案时,您应该避免针对同一个问题发布多个答案。
【解决方案3】:

内存问题最终是 ImageNamed 方法。一旦我使用另一种方法覆盖它,一切似乎都正常。

@implementation UIImage(imageNamed_Hack)
+ (UIImage *)imageNamed:(NSString *)name {
    return [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:name ofType:nil]];
}
@end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-04-30
    • 2011-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-20
    相关资源
    最近更新 更多