【问题标题】:Most memory efficient way to save a photo to disk on iPhone?在 iPhone 上将照片保存到磁盘的最节省内存的方法?
【发布时间】:2014-01-07 08:13:12
【问题描述】:

通过使用Instruments 进行分析,我了解到我将图像保存到磁盘的方式会导致~60MB 的内存峰值。这会导致应用程序发出 low memory warnings,这(不一致地)导致运行 iOS7iPhone4S 崩溃。

我需要最有效的方式将图像保存到磁盘。

我目前正在使用此代码

+ (void)saveImage:(UIImage *)image withName:(NSString *)name {
    NSData *data = UIImageJPEGRepresentation(image, 1.0);
    DLog(@"*** SIZE *** : Saving file of size %lu", (unsigned long)[data length]);
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:name];
    [fileManager createFileAtPath:fullPath contents:data attributes:nil];
}

注意事项:

  1. 减少UIImageJPEGRepresentationcompressionQuality 参数的值并不能显着减少内存峰值。 例如 compressionQuality = 0.8,平均比100 写入减少了3MB 的内存峰值。 但是,它确实减少了磁盘上数据的大小(显然),但这对我没有帮助。

  2. UIImagePNGRepresentation 代替 UIImageJPEGRepresentation 对此更糟。它速度较慢,并导致更高的尖峰。

this approachImageIO 是否可能更有效?如果有,为什么?

如果有人有任何建议,那就太好了。谢谢

编辑:

关于以下问题中概述的一些要点的注释。

a) 虽然我保存了多张图片,但我并没有将它们保存在一个循环中。我做了一些阅读和测试,发现自动释放池对我没有帮助。

b) 每张照片的大小都不是 60Mb。它们是在 iPhone 4S 上拍摄的。

考虑到这一点,我回去尝试克服我认为的问题;行NSData *data = UIImageJPEGRepresentation(image, 1.0);

可以在下面的屏幕截图中看到导致崩溃的内存峰值。它们对应于调用UIImageJPEGRepresentation 的时间。我还跑了Time ProfilerSystem Usage,这为我指明了相同的方向。

长话短说,我搬到AVFoundation 并使用

photoData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];

它返回一个NSData 类型的对象,然后我将其用作使用NSFileManager 写入的数据。

这完全消除了内存中的峰值。

[self saveImageWithData:photoData];

在哪里

+ (void)saveImageWithData:(NSData *)imageData withName:(NSString *)name {
    NSData *data = imageData;
    DLog(@"*** SIZE *** : Saving file of size %lu", (unsigned long)[data length]);
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:name];
    [fileManager createFileAtPath:fullPath contents:data attributes:nil];
}

PS:如果人们觉得它没有回答标题“在 iPhone 上将照片保存到磁盘的最节省内存的方法?”,我没有把它作为问题的答案。但是,如果共识是应该的,我可以更新它。

谢谢。

【问题讨论】:

  • 您说的是内存和磁盘数据。只有在内存中会导致应用程序被强制终止。你在内存中保留了哪些你不需要的东西。如果图像很大,那么您需要以不同的方式使用它...
  • 我知道。我也在问题中说明了这一点。即“但是,它确实减少了磁盘上数据的大小(显然)但这对我没有帮助。”您的评论“如果图像很大,那么您需要以不同的方式使用它”没有帮助。
  • 我认为saveImage:withName 不是问题。这可能是您调用此函数的方式。提供使用此功能的代码,人们可以帮助您。
  • 因此,请关注内存中的情况,并详细说明有多少图像,在保存之前如何处理它们,它们有多大......
  • 我同意。将其发布为答案;如果出现更好的情况,您可以随时移动复选标记。

标签: ios iphone objective-c uiimage avfoundation


【解决方案1】:

使用 UIImageJPEGRepresentation 要求您在内存中同时拥有原始图像和最终图像。它还可能将完全渲染的图像缓存一段时间,这会占用大量内存。

您可以尝试使用CGImageDestination。我不知道它的内存效率如何,但它有可能将图像直接流式传输到磁盘。

+(void) writeImage:(UIImage *)inImage toURL:(NSURL *)inURL withQuality:(double)inQuality {
    CGImageDestinationRef destination = CGImageDestinationCreateWithURL( (CFURLRef)inURL , kUTTypeJPEG , 1 , NULL );
    CFDictionaryRef properties = (CFDictionaryRef)[NSDictionary dictionaryWithObject:[NSNumber numberWithDouble:inQuality] forKey:kCGImageDestinationLossyCompressionQuality];
    CGImageDestinationAddImage( destination , [inImage CGImage] , properties );
    CGImageDestinationFinalize( destination );
    CFRelease( destination );
}

【讨论】:

  • 我刚刚对此进行了测试,我看到与上面概述的 UIImageJPEGRepresentation 方法相同的内存峰值。
  • 加一,因为它降低了 10% 的内存使用。但仍然不是解决方案
【解决方案2】:

您的图片实际上是 60MB 压缩的吗?如果是,那么如果要将它们保存为单个 JPEG 文件,则无能为力。您可以尝试将它们渲染成更小的图像,或者将它们平铺并保存到单独的文件中。

我不希望您的 ImageIO 代码 sn-p 有任何改进。如果有两行修复,那么UIImageJPEGRepresentation 将在内部使用它。

但我敢打赌,您不会从单个图像中获得 60MB。我打赌你会从循环保存的多个图像中获得 60MB。如果是这种情况,那么您可能会做一些事情。将@autoreleasepool{} 放入循环中。您很有可能正在累积自动释放的对象,这导致了峰值。在循环中添加一个池可以让它排干。

【讨论】:

    【解决方案3】:

    一旦你完成写入数据,尝试使用 NSAutoReleasePool 并排空池。

    【讨论】:

    • 虽然这可能会有所帮助,但它非常神秘且缺乏很多上下文。请考虑扩展您的答案,使其对其他人更有用。
    猜你喜欢
    • 2016-10-07
    • 1970-01-01
    • 2010-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-29
    • 2010-12-01
    • 1970-01-01
    相关资源
    最近更新 更多