2013-12-18 28 views
14

從配置文件Instruments我瞭解到,我將映像保存到磁盤的方式導致內存峯值達到~60MB。這導致應用程序發出low memory warnings,這(不一致)導致iPhone4S運行iOS7上的崩潰。大多數內存有效的方式來保存照片到iPhone上的磁盤?

我需要最有效的方式將圖像保存到磁盤。

我目前使用此代碼

+ (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)雖然我保存了多個圖像,但我並沒有將它們保存在循環中。我做了一些閱讀和測試,發現一個autorelease池不會幫助我。

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上的磁盤?「。但是,如果共識是應該的,我可以更新它。

謝謝。

+0

您正在討論內存中和磁盤上的數據。只有內存導致應用程序被強制終止。你記憶中的東西你不需要。如果圖像很大,那麼你需要以不同的方式使用它... – Wain

+2

我知道這一點。我也在這個問題中說明。即「但是,它確實減少了磁盤上的數據大小(顯然),但這對我沒有幫助。」您的評論「如果圖片很大,那麼您需要以不同的方式使用它」無濟於事。 –

+0

因此,專注於內存的情況,並提供更多的圖像,他們如何處理之前,你來保存,他們是多大的細節... – Wain

回答

2

您的圖像實際上是60MB壓縮的嗎?如果是的話,如果您想將它們保存爲單個JPEG文件,則可以做的事情不多。您可以嘗試將它們渲染爲較小的圖像,或將它們平鋪並將它們保存到單獨的文件中。

我不希望你的ImageIO代碼片段改善任何東西。如果有兩行修正,則UIImageJPEGRepresentation將在內部使用它。

但我敢打賭,你沒有從單個圖像獲得60MB。我打賭你從循環中保存的多個圖像獲得60MB。如果是這樣的話,那麼你可能會做一些事情。在你的循環中放入@autoreleasepool{}。你很可能積累了自動釋放的對象,這導致了高峯。在你的循環內添加一個池可以讓它流失。

3

使用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

我剛剛測試過,並且看到與上面列出的UIImageJPEGRepresentation方法相同的內存尖峯。 – dokkaebi

+0

加1,因爲它的內存使用率降低了10%。但仍然不是解決方案 – hasan83

-1

嘗試使用NSAutoReleasePool並在您完成寫入數據後耗盡池。

+2

雖然這可能會有所幫助,但它非常神祕而且缺乏大量的上下文。請考慮擴大您的答案,以使其對其他人更有用。 – djikay