Самый эффективный способ сохранения фотографии на диск на iPhone?

Из профилирования с помощью Instruments Я узнал, что способ сохранения изображений на диск приводит к всплескам памяти до ~60MB. Это приводит к появлению приложения low memory warnings, которое (непоследовательно) приводит к сбоям на iPhone4S running 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];
}

Примечание:

  • Уменьшение значения аргумента compressionQuality в UIImageJPEGRepresentation не позволяет значительно уменьшить всплеск памяти. например compressionQuality = 0.8, уменьшился всплеск памяти на 3MB в среднем за 100. Тем не менее, он уменьшает размер данных на диске (очевидно), но это не помогает мне.

  • UIImagePNGRepresentation вместо UIImageJPEGRepresentation для этого хуже. Он медленнее и приводит к более высоким всплескам.

Возможно ли, что этот подход с ImageIO будет более эффективным? Если да, то почему?

Если у кого-то есть предложения, было бы здорово. Благодаря

Edit:

Примечания к некоторым пунктам, указанным в нижеприведенных вопросах.

a) Хотя я сохранял несколько изображений, я не сохранял их в цикле. Я немного читал и тестировал и обнаружил, что пул авторесурсов мне не поможет.

b) Фотографии не были размером 60 Мб каждого. Это были фотографии, сделанные на iPhone 4S.

С учетом этого я вернулся к попытке преодолеть то, что я думал о проблеме; строка NSData *data = UIImageJPEGRepresentation(image, 1.0);.

Пики памяти, вызывающие крушение, можно увидеть на скриншоте ниже. Они соответствовали, когда был вызван UIImageJPEGRepresentation. Я также запускал Time Profiler и System Usage, которые указывали мне в одном направлении.

enter image description here

Короче говоря, я перешел на AVFoundation и взял данные фотоизображения, используя

photoData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];

Возвращает объект типа NSData, затем я использовал это как данные для записи с использованием NSFileManager.

Это полностью удаляет всплески в памяти.

i.e

[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: Я не считаю это ответом на вопрос, если люди считают, что он не отвечает на Title "Самый эффективный способ сохранения фотографии на диск на iPhone?". Однако, если консенсус заключается в том, что я должен обновить его.

Спасибо.

Ответы

Ответ 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 );
}

Ответ 2

Являются ли ваши изображения на самом деле сжатыми 60 МБ, каждый? Если они есть, вы не можете много сделать, если хотите сохранить их как один файл JPEG. Вы можете попробовать их преобразовать на более мелкие изображения, или пометить их и сохранить в отдельных файлах.

Я не ожидаю, что ваш фрагмент кода ImageIO улучшит что-либо. Если было двухстрочное исправление, то UIImageJPEGRepresentation будет использовать его внутри.

Но я уверен, что вы не получите 60 МБ от одного изображения. Я уверен, вы получите 60 МБ от нескольких изображений, сохраненных в цикле. И если это так, то есть что-то, что вы можете сделать. Поместите @autoreleasepool{} внутри вашего цикла. Вполне возможно, что вы накапливаете объекты с автореализацией, и это приводит к всплеску. Добавление пула внутри вашего цикла позволяет ему сливаться.

Ответ 3

Попробуйте использовать NSAutoReleasePool и слейте пул после завершения записи данных.