我在使用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];
}发布于 2014-08-12 04:34:24
使用UIImageJPEGRepresentation (其中通过UIImage往返资源)可能会出现问题,因为使用1.0的compressionQuality时,生成的NSData实际上可能比原始文件大得多。(另外,您在UIImage中保存了图像的第二个副本。)
例如,我刚刚从iPhone的图片库中随机挑选了一张图片,原始图片的大小是1.5mb,但由UIImageJPEGRepresentation制作的compressionQuality为1.0的NSData需要6.2mb。而且,在UIImage中保存图像本身可能会占用更多的内存(因为如果未压缩,则可能需要每个像素4个字节)。
相反,您可以使用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 (无论如何对于照片而言)可以小得多。请注意,这也有一个优点,即它还保留了与图像关联的元数据。
顺便说一句,虽然上面的代码代表了显著的内存改进,但您可能会看到一个更显著的内存减少机会:具体地说,您现在可以流式传输资产(子类NSInputStream,以便在需要时使用此getBytes例程获取字节,而不是一次性将整个内容加载到内存中),而不是一次性将整个资产加载到NSData中。这个过程有一些麻烦(请参阅BJ Homer's article on the topic),但如果您希望显著减少内存占用,这就是解决办法。这里有几种方法(BJ的,使用一些临时文件和流媒体,等等),但关键是流媒体可以显着减少你的内存占用。
但是,通过在UIImageJPEGRepresentation中避免使用UIImage (它避免了图像占用的内存以及UIImageJPEGRepresentation产生的更大的NSData ),您也许能够取得相当大的进展。此外,您可能希望确保内存中没有此图像数据的冗余副本(例如,不要将图像数据加载到NSData中,然后为HTTPBody构建第二个NSData ...看看你能不能一举完成)。如果最坏的情况变得更糟,你可以采用流媒体方法。
发布于 2016-07-29 23:06:50
在ARC中:只需将您的代码放在@autoreleasepool的小块中
@autoreleasepool {
NSData *data = UIImageJPEGRepresentation(img, 0.5);
// something with data
}发布于 2014-08-12 01:38:48
作为格式化和图像的答案。
使用仪器检查由于保留但不是泄漏的内存而导致的泄漏和内存丢失。后者是仍然指向的未使用的内存。在仪器上的分配工具中使用标记生成(堆快照)。
有关使用堆快照查找内存碎片的信息,请参阅:bbum blog
基本上,该方法是运行Instruments allocate工具,获取堆,运行代码的迭代,并重复3到4次获取另一次堆。这将指示在迭代期间分配的和未释放的内存。
要弄清楚结果,请查看各个分配。
如果您需要查看对象的保留位置、释放位置和自动释放位置,请使用仪器:
在仪器中运行,在分配中设置"Record reference counts“on (对于Xcode 5和更低版本,您必须停止记录以设置该选项)。使应用程序运行,停止录制,向下钻取,您将能够看到所有保留、释放和自动释放发生的位置。

https://stackoverflow.com/questions/25248294
复制相似问题