Использование UIImageJPEGRepresentation
(в котором вы выполняете циклический обход ресурса через UIImage
) может быть проблематичным, поскольку при использовании compressionQuality
, равного 1,0, результирующий NSData
может быть значительно больше, чем исходный файл. (Кроме того, у вас есть вторая копия изображения в UIImage
.)
Например, я просто выбрал случайное изображение из фотобиблиотеки своего iPhone, исходный актив весил 1,5 МБ, но для NSData
, созданного UIImageJPEGRepresentation
с compressionQuality
1,0, требовалось 6,2 МБ. И само хранение изображения в UIImage
может занять еще больше памяти (потому что в несжатом виде может потребоваться, например, четыре байта на пиксель).
Вместо этого вы можете получить исходный актив, используя метод getBytes
:
static NSInteger kBufferSize = 1024 * 10;
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSURL *url = info[UIImagePickerControllerReferenceURL];
[self.library assetForURL:url resultBlock:^(ALAsset *asset) {
ALAssetRepresentation *representation = [asset defaultRepresentation];
long long remaining = representation.size;
NSString *filename = representation.filename;
long long representationOffset = 0ll;
NSError *error;
NSMutableData *data = [NSMutableData data];
uint8_t buffer[kBufferSize];
while (remaining > 0ll) {
NSInteger bytesRetrieved = [representation getBytes:buffer fromOffset:representationOffset length:sizeof(buffer) error:&error];
if (bytesRetrieved <= 0) {
NSLog(@"failed getBytes: %@", error);
return;
} else {
remaining -= bytesRetrieved;
representationOffset += bytesRetrieved;
[data appendBytes:buffer length:bytesRetrieved];
}
}
// you can now use the `NSData`
} failureBlock:^(NSError *error) {
NSLog(@"assetForURL error = %@", error);
}];
}
Это позволяет избежать помещения изображения в UIImage
, а результирующий NSData
может быть (во всяком случае, для фотографий) значительно меньше. Обратите внимание, что это также имеет то преимущество, что оно также сохраняет метаданные, связанные с изображением.
Между прочим, в то время как приведенное выше представляет собой значительное улучшение памяти, вы, вероятно, можете увидеть более существенную возможность сокращения памяти: в частности, вместо того, чтобы загружать весь ресурс в NSData
за один раз, теперь вы можете передавать ресурс (подкласс NSInputStream
для использования эта процедура getBytes
для выборки байтов по мере необходимости, а не для загрузки всего в память за один раз). С этим процессом связаны некоторые неудобства (см. статью Б. Дж. Гомера на эту тему), но если вы ищете резкое сокращение объема памяти, то это именно то, что вам нужно. Здесь есть несколько подходов (BJ, использование некоторого промежуточного файла и потоковой передачи из него и т. д.), но ключ в том, что потоковая передача может значительно уменьшить объем памяти.
Но избегая UIImage
в UIImageJPEGRepresentation
(что позволяет избежать памяти, занимаемой изображением, а также большего NSData
, которое дает UIImageJPEGRepresentation
), вы можете значительно продвинуться вперед. Кроме того, вы можете захотеть убедиться, что у вас нет избыточных копий данных этого изображения в памяти одновременно (например, не загружайте данные изображения в NSData
, а затем создайте второй NSData
для HTTPBody
... посмотрите, сможете ли вы сделать это одним махом). И если случится худшее, вы можете использовать потоковую передачу.
person
Rob
schedule
11.08.2014
openURL
не всегда запускается, но успешно ли завершается загрузка изображения? Думаю, я спрашиваю, определили ли вы проблему какopenURL
или, возможно, что-то до этого... - person Rob   schedule 12.08.2014