【问题标题】:Memory Leak Downloading image from server内存泄漏从服务器下载图像
【发布时间】:2013-03-05 19:11:21
【问题描述】:

我有一个分页滑块视图,每个页面上都有一个图像。我正在使用NSOperationQueue 在程序运行时帮助我从服务器下载图像。 NSOperationQueue用于调用如下方法,

-(NSData *)imageWith:(NSString *)imageName
{

NSString *imagePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:imageName];
NSData *imageData = [NSData dataWithContentsOfFile:imagePath];

if (!imageData) {

   imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:[[NSString stringWithFormat:@"%@/%@", picsURL,imageName] stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]]];

    if (imageData) {

        [imageData writeToFile:imagePath atomically:YES];
    }
}     
 return imageData;
}

然后我使用主线程在滚动视图上显示下载的图像:

[self performSelectorOnMainThread:@selector(loadPic:) withObject:[NSArray arrayWithObjects:[self imageWith:[picsNames objectAtIndex:imageView.tag]], [NSString stringWithFormat:@"%d", imageView.tag], nil] waitUntilDone:YES];

调用如下方法:

-(void)loadPic:(NSArray *)imageAndTagArray
{
    if (imageAndTagArray.count) {

    //loading the image to imageview
    UIImageView *imageView = (UIImageView *)[scrollView viewWithTag:[[imageAndTagArray objectAtIndex:1] intValue]];
    imageView.image = [UIImage imageWithData:((NSData *)[imageAndTagArray objectAtIndex:0])];

    //stopping the indicator
    [((UIActivityIndicatorView *)[imageView viewWithTag:ACTIVITY_INDICATOR_TAG]) stopAnimating];
}
}

前 60 张图片一切正常,但之后我收到内存警告,大约 100 张图片后应用崩溃。

我在这方面花了很多时间,但我不知道该怎么办。我用过 Instruments,它没有检测到任何泄漏。我也使用了分析,它也显示了任何东西。

编辑:

如果我将 imageWith: 方法定义替换为以下定义,我仍然会收到警告,其中 5.jpg 是本地图像。

-(NSData *)imageWith:(NSString *)imageName
{
     return UIImagePNGRepresentation([UIImage imageNamed:@"5.jpg"]);
}

让我告诉你更多的情况。

当应用程序启动时,我有一个视图,里面有一个分页滚动视图,每页包含 9 个图像。滚动视图使用 nsoperationqueue 加载调用 imageWith: 方法的图像。

当用户点击任何图像时,会打开第二个视图,其中会完整显示所选图像。第二个视图也有一个滚动视图,其中包含与第一个视图相同的图像,但具有完整显示,即每页一张图像。

当您在第二个视图上来回滚动时,应用程序在加载大约 60 张图像后崩溃。 如果说它加载了 50 张图片,然后您点击后退按钮并转到第一个视图,然后点击另一张图片并转到第二个视图并加载大约 10 张图片,它也会崩溃。

【问题讨论】:

  • 你在使用自动引用计数吗?
  • 您可能只是在内存中保留了太多内容。您是否曾经发布过您在图像视图上设置的图像(例如,当用户将它们滚动到屏幕外时)?
  • 是的,我在 xCode 4.6 中使用自动引用计数
  • 谢谢蒂姆。它只是从磁盘读取图像数据时崩溃。例如,当我运行程序一次并且所有内容都存储在磁盘上时。我第二次运行它,它只是在将一些图像加载到它崩溃的图像视图后从磁盘读取。
  • 我编辑了我的问题并进一步解释了情况。

标签: ios image memory memory-leaks


【解决方案1】:

听起来您在内存中保存了太多图像。当您打开第二个视图时,它会再次从磁盘重新加载图像,直到您最终得到所有图像的两个副本。

UIImage 类可能能够帮助您进行这种内存管理。在其reference page 中,它提到它能够在内存不足的情况下清除其数据,然后在需要再次绘制文件时从磁盘重新加载文件。这可能是您的解决方案。

但是,当您从磁盘读取的 NSData 创建图像时,UIImage 可能无法清除其内存 - 它不会知道您的图像只是存储在磁盘上,因此它可以t 丢弃数据并稍后重新加载。

尝试更改您的“imageWith”方法以在它返回之前从磁盘上的文件 URL 创建一个 UIImage(通过 imageWithContentsOfFile),并返回 UIImage 而不是返回中间的 NSData。这样,UIImage 将知道其图像源在磁盘上的哪个位置,并能够在设备内存受限时智能地清除/重新加载它。

【讨论】:

  • “听起来你在内存中保存了太多图像。”你是对的。所以我所做的是我更改了代码,所以当时我只有 10 个 uiimage。并且没有更多的内存警告。
  • 我也更改为 imageWithContentsOfFile 并返回 UIimage 而不是 nsdata 如你所建议的。它在内存警告的情况下没有任何区别,但它听起来更有效率,所以我就是这样做的。
  • 非常感谢您的帮助。你帮了我很多,我感激不尽:)
猜你喜欢
  • 2018-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-27
  • 2016-08-10
  • 2011-07-21
  • 1970-01-01
相关资源
最近更新 更多