大多数内存有效的方法将照片保存到iPhone上的磁盘?

时间:2013-12-18 22:54:34

标签: ios iphone objective-c uiimage avfoundation

从使用Instruments进行分析后,我了解到将图像保存到磁盘的方式会导致内存峰值~60MB。这会导致应用程序发出low memory warnings,这会导致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];
}

说明:

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

  2. UIImagePNGRepresentation取代UIImageJPEGRepresentation对此更糟糕。速度较慢,导致峰值较高。

  3. this approachImageIO的效率是否更高?如果是这样的话?

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

    修改

    注意以下问题中列出的一些要点。

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

    b)照片的大小各不为60Mb。他们是在iPhone 4S上拍摄的照片。

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

    导致崩溃的内存峰值可以在下面的屏幕截图中看到。他们对应于UIImageJPEGRepresentation被召唤的时间。我还跑Time ProfilerSystem Usage,这使我指向了同一个方向。

    enter image description here

    长话短说,我转到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上将照片保存到磁盘上的大多数内存有效的方法吗?”。但是,如果达成共识,我应该更新它。

    感谢。

3 个答案:

答案 0 :(得分:4)

使用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 );
}

答案 1 :(得分:2)

你的图片实际上是60MB压缩的吗?如果它们是,如果您想将它们保存为单个JPEG文件,则无法做很多事情。您可以尝试将它们渲染为较小的图像,或者将它们平铺并将它们保存到单独的文件中。

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

但是我打赌你没有从单张图片中获得60MB。我打赌你从循环中保存的多个图像中获得60MB。如果是这样的话,那么你可以做些什么。在您的循环中放置@autoreleasepool{}。很可能你正在积累自动释放的物体,这导致了尖峰。在循环中添加一个池可以让它耗尽。

答案 2 :(得分:-1)

尝试使用NSAutoReleasePool并在完成数据写入后将池耗尽。