大多数内存有效的方式来保存在iPhone上的照片到磁盘?
从Instruments
分析我了解到,我将图像保存到磁盘的方式导致内存峰值~60MB
。 这导致应用程序发出low memory warnings
,这(不一致)导致运行iOS7
的iPhone4S
上的iOS7
。
我需要最有效的方法将图像保存到磁盘。
我目前正在使用这个代码
+ (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]; }
笔记:
-
减less
UIImageJPEGRepresentation
中的compressionQuality
参数的值不会显着减less内存尖峰。 例如compressionQuality = 0.8
,平均超过100
写入,内存尖峰减less了3MB
。 但是,它确实减less了磁盘上的数据的大小(显然),但是这对我没有帮助。 -
UIImagePNGRepresentation
代替UIImageJPEGRepresentation
对此更糟糕。 速度较慢,导致峰值较高。
ImageIO
这种方法可能会更有效吗? 如果是这样的话
如果有人有任何build议,这将是伟大的。 谢谢
编辑:
请注意以下问题中列出的一些要点。
a)尽pipe我保存了多个图像,但我并没有将它们保存在一个循环中。 我做了一些阅读和testing,发现一个autorelease池不会帮助我。
b)照片不是每个60Mb的大小。 他们是在iPhone 4S拍摄的照片。
考虑到这一点,我回到了试图克服我所认为的问题; 行NSData *data = UIImageJPEGRepresentation(image, 1.0);
。
在下面的屏幕截图中可以看到导致崩溃的内存尖峰。 它们对应于何时UIImageJPEGRepresentation
。 我也运行Time Profiler
和System Usage
,指出我在同一个方向。
长话短说,我转移到AVFoundation
并使用照片图像数据
photoData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
它返回一个NSData
types的对象,然后我使用这个作为数据使用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上将照片保存到磁盘上的最有效的方法”。 但是,如果共识是应该的,我可以更新它。
谢谢。
使用UIImageJPEGRepresentation要求您同时在内存中具有原始和最终的图像。 它也可能会caching完整的渲染图像一段时间,这将使用大量的内存。
你可以尝试使用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 ); }
你的图像实际上是60MB压缩,每个? 如果是的话,如果你想把它们保存为一个单独的JPEG文件,那么你可以做的不多。 您可以尝试将它们渲染为较小的图像,或将它们拼贴并保存为单独的文件。
我不希望你的ImageIO代码片段改善任何东西。 如果有两行修正,那么UIImageJPEGRepresentation
将在内部使用它。
但是我敢打赌,你从单张图片中得不到60MB。 我打赌你从循环中保存的多个图像获得60MB。 如果是这样的话,那么你可能会做些什么。 把一个@autoreleasepool{}
放到你的循环中。 这是很有可能的,你积累自动释放对象,这是导致穗。 在你的循环中添加一个池允许它stream失。
尝试使用NSAutoReleasePool,一旦完成写入数据,就会排空游泳池。