内存泄漏与UIImages

时间:2013-12-15 00:00:03

标签: ios objective-c memory-leaks

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.predictionsObjectArray = [[AAPredictions alloc] init];
    self.animationImagesMutableArray = [NSMutableArray new];

    [self.predictionsObjectArray setPredictionsArray:@[@"Probably Not", @"Ask Again", @"I doubt it", @"Unlikely", @"I believe so"]];

    for (int x = 1; x<61; x++) {
        NSMutableString *imageName = [[NSMutableString alloc] init];
        if (x > 9) {
            imageName = [NSMutableString stringWithFormat:@"CB000%i.png", x];
        }
        else {
           imageName = [NSMutableString stringWithFormat:@"CB0000%i.png", x];
        }
        [self.animationImagesMutableArray addObject:[UIImage imageNamed:imageName]];
    }
    self.background_image.animationImages = self.animationImagesMutableArray;
    self.animationImagesMutableArray = NULL;
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark Prediction

-(void)makePrediction {
    self.predictionLabel.text = [self.predictionsObjectArray getPrediction];
    [self animateItems];
}

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag {
    if (flag == true) {
        self.image_button.alpha = 1;
    }
}

-(void)animateItems {
    self.image_button.alpha = 0.0;
    self.background_image.animationRepeatCount = 1;
    if (self.background_image.animationImages == NULL) {
        self.background_image.animationImages = self.animationImagesMutableArray;
    }
    self.background_image.animationDuration = 3;
    [self.background_image startAnimating];
    [self performSelector:@selector(postAnimation) withObject:nil afterDelay:4.25];
}

-(void)postAnimation {
    self.image_button.alpha = 1;
    self.background_image.animationImages = NULL;
}

#pragma mark Actions

-(void) motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {
    if (self.background_image.isAnimating != true) {
        [self makePrediction];
    }
}

- (IBAction)button_pushed {
    if (self.background_image.isAnimating != true) {
        [self makePrediction];
    }
}
@end

我是编程新手,正在网上上课,不得不创建一个crystalBall应用程序。我想更进一步,添加一个按钮功能。因此,按钮基本上是水晶球出现并消失(在动画期间消失)。我最近几天得不到的问题是在调试器中我调用makePrediction函数后将所有图像存储在内存中...它大约是187MB。我知道它不是很多,但应用程序以27MB开始。我如何从内存中释放它然后每次调用该函数时将图像恢复到background_image.animationImages?

2 个答案:

答案 0 :(得分:2)

有几点想法:

  1. 通过图像阵列制作动画的方法永远是对内存的过度使用。如果这样做,您可能希望减少图像数量,或减少单个图像的尺寸。

    要了解此技术使用了多少内存,假设每个图像每像素4个字节。因此,800px x 800px的60幅图像占用146mb。不要查看JPG或PNG文件的大小来确定图像占用的内存量。这些是压缩格式,但是当图像加载到UIKit控件中时,它是未压缩的,每像素占4个字节。

  2. 正如其他人所指出的,使用imageNamed会缓存图像,这会阻止在释放图像时释放内存。您可以考虑使用imageWithContentsOfFile代替。您将失去缓存的性能增益,但您不应该遇到它所带来的内存使用问题。

  3. 你可能想让我们知道“水晶球出现和消失”动画的样子。问题是你是否可以实现所需的动画,而不用拥有不同图像的数组。

    通常你只有一个图像(完全消除了这个内存问题),然后为一些可动画的属性设置动画(例如alpha使其淡入或淡出视图,frame如果你想要的话它可以滑入或滑出或挤入和挤出,transform可以缩放/移动它等等。只有一个图像,然后动画其中一个属性是处理动画的更有效的内存方式。例如,让它淡出:

    [UIView animationWithDuration:0.5
                       animations:^{
                           self.crystalBall.alpha = 0.0;
                       }];
    

    你必须告诉我们更多关于这个动画应该是什么样的东西,以便我们进一步帮助你。

  4. 底线,将所有这些图像加载到内存中是奢侈的,您想要最小化每个图像的大小,减少图像数量,或者完全退出这个“图像阵列”概念并移动到某些{{1基于块的动画。

答案 1 :(得分:0)

所以这是一个老问题,但imageNamed会将图像缓存在内存中,它专为小型可重复使用的图像设计,如按钮,图标等。我认为如果你有内存压力,你会看到内存压力有所改善使用未缓存的imageWithContentsOfFile

SO上有一个非常棒的answer,可以更详细地讨论这个问题。