使用UIImageJPEGRepresentation时收到内存警告,有什么方法可以避免这种情况吗?它并没有让应用程序崩溃,但我想尽可能避免使用它。它间歇性地不运行[[UIApplication sharedApplication] openURL:url];
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *image = [info valueForKey:UIImagePickerControllerOriginalImage];
NSData *imageToUpload = UIImageJPEGRepresentation(image, 1.0);
// code that sends the image to a web service (omitted)
// on success from the service
// this sometime does not get run, I assume it has to do with the memory warning?
[[UIApplication sharedApplication] openURL:url];
}
答案 0 :(得分:5)
使用UIImageJPEGRepresentation
(您通过UIImage
对资产进行往返)可能会有问题,因为使用compressionQuality
为1.0,结果NSData
可以实际上比原始文件大得多。 (另外,您在UIImage
中持有图像的第二份副本。)
例如,我刚刚从iPhone的照片库中选择了一张随机图片,原始资源为1.5mb,但NSData
生成的UIImageJPEGRepresentation
只有compressionQuality
1.0需要6.2mb。将图像保存在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 Homer's article on the topic),但是如果你正在寻找内存占用的显着减少,那就是这样。这里有几种方法(BJ&#39; s,使用一些暂存文件和流式传输等),但关键是流式传输可以大大减少你的内存占用。
但是通过避免UIImage
中的UIImageJPEGRepresentation
(这会避免图像占用的内存以及NSData
产生的较大UIImageJPEGRepresentation
),您可以取得很大进展。此外,您可能希望确保一次不在内存中存储此图像数据的冗余副本(例如,不要将图像数据加载到NSData
中,然后构建一个NSData
的第二个HTTPBody
...看看你能否一举做到这一点。如果情况变得更糟,你可以采用流媒体方式。
答案 1 :(得分:3)
:只需将您的代码放在@autoreleasepool
的小块中 @autoreleasepool {
NSData *data = UIImageJPEGRepresentation(img, 0.5);
// something with data
}
答案 2 :(得分:1)
作为格式和图像的答案。
使用仪器检查由于保留但未泄漏的内存导致的泄漏和内存丢失。后者是未使用的内存,仍然指向。在仪器上的分配工具中使用标记生成(快照)。
如何使用“快照”查找内存褶皱,请参阅:bbum blog
基本上,该方法是运行Instruments分配工具,获取快照,运行代码的迭代并重复另外3到4次快照。这将指示在迭代期间分配但未释放的内存。
要弄清楚披露的结果,以查看个别分配。
如果您需要查看对象使用仪器的保留,释放和自动释放的位置:
在仪器中运行,在分配中设置&#34;记录参考计数&#34; on(对于Xcode 5及更低版本,您必须停止录制以设置选项)。导致应用程序运行,停止录制,向下钻取,您将能够看到所有保留,发布和自动释放的位置。