来自 UIImageView 的内存泄漏
Posted
技术标签:
【中文标题】来自 UIImageView 的内存泄漏【英文标题】:Memory Leak from UIImageView 【发布时间】:2014-01-23 16:09:22 【问题描述】:我目前在 ios7 中进行个人项目,我必须在 Galarie 滚动视图上显示几张图像。为此,我创建了一个UIImage
,然后将其插入UIImageView
。我将我所有的UIImageView
存入NSMutableArray
。
我在UIScrollView
上显示所有图片。
通过我可以执行的测试,使用的内存可以超过 500 MB。
如何优化内存?您如何使用相机基础应用程序显示 1000 多张照片?
提前谢谢你。诚挚的。
【问题讨论】:
在未全屏显示时延迟加载和制作图像缩略图。 【参考方案1】:您需要根据滚动视图位置设置延迟加载。只加载三倍可见屏幕(或更少,取决于内存需要)并实现 UIScrollViewDelegate 函数scrollviewDidScroll:
来监听滚动事件。
在 scrollViewDidScroll 中,您将要搜索图像数组(它应该是位置和文件名数组,以获得最佳内存释放)。如果滚动视图接近您的图像位置,则加载它并将其添加到屏幕。如果某些东西已经在屏幕上,但现在已经足够远离屏幕并卸载了,则将其从滚动视图中移除并释放对象(或者更好地,将其重新用于下一次图像加载)。
查看 PDFKitten。他们会延迟加载 PDF 页面。您的图像可以以完全相同的方式实现。
【讨论】:
【参考方案2】:UICollectionView 更适合你的问题!
UICollectionView 和 UITableView 一样,只是加载显示在屏幕上的单元格。
UICollectionView 是一个滚动视图,但具有内存管理功能。
【讨论】:
您好,我尝试了 UICollectionView,但我不知道。它非常强大,但我还没有记忆问题。这是一个疯狂的情况。我会尝试压缩 UIImage。 这不是 OPs 问题的解决方案 user2724028,这很奇怪,因为通常 collectionview 会卸载未显示的单元格。也许发布一些代码。【参考方案3】:几年前,当我在 UIImageViews 中使用全尺寸图片时,我遇到了同样的问题。我的应用在实际的 iPhone 4 上一直内存不足。由于某种原因,它在 iPhone 模拟器上运行良好。
您必须使用“UIImage+Resize”缩小原始图像才能在 UIScrollView 中显示预览图像。当用户点击其中一张图片时,您可以向他们展示更大/完整的版本。
Download it from here.
CGSize buttonSize = CGSizeMake(100, 100);
UIImage * newImage = [[UIImage alloc] initWithContentsOfFile: pathToImage];
if(newImage)
// this "resizedimage" image is what you want to pass to setImage
UIImage * resizedImage = [newImage resizedImage: buttonSize interpolationQuality: kCGInterpolationLow];
【讨论】:
【参考方案4】:简单的解决方案是将原始图像保存到目录并将调整大小的图像分配给滚动视图。此解决方案将使您能够以最少的内存使用向滚动视图添加更多数量的图像。这是示例代码
-(IBAction)selectImageBtnClicked:(id)sender
UIImagePickerController * picker = [[UIImagePickerController alloc] init]; picker.delegate = self; picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; [self presentViewController:picker animated:YES completion:nil]; [picker release];
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
[picker dismissViewControllerAnimated:YES completion:nil]; [[picker parentViewController] dismissViewControllerAnimated:YES
完成:无];
UIImage *pTakenImage = [info objectForKey:UIImagePickerControllerEditedImage]; if (!pTakenImage) pTakenImage = [info objectForKey:UIImagePickerControllerOriginalImage]; [self performSelectorOnMainThread:@selector(proceedFURTHER:)
withObject:pTakenImage waitUntilDone:NO];
-(void) 继续: (UIImage*)pTakenImage UIImage *pResizedImage = [self resizeImageToMaxSize:640.0 anImage:pTakenImage];
[self saveOriginalImageToDir:pTakenImage]; //add pResizedImage to your scrolview here [self.navigationController popViewControllerAnimated:YES];
-(UIImage*)resizeImageToMaxSize:(CGFloat)max anImage:(UIImage*)anImage
NSData * imgData = UIImageJPEGRepresentation(anImage, 1); CGImageSourceRef imageSource =
CGImageSourceCreateWithData((CFDataRef)imgData, NULL); 如果 (!imageSource) 返回零;
CFDictionaryRef options =
(CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:
(id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailWithTransform,
(id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailFromImageIfAbsent,
(id)[NSNumber numberWithFloat:max], (id)kCGImageSourceThumbnailMaxPixelSize, nil];
CGImageRef imgRef =
CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options);
UIImage* scaled = [UIImage imageWithCGImage:imgRef]; CGImageRelease(imgRef); CFRelease(imageSource); return scaled;
-(NSString*)getOriginalImageDirectoryPath
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask,是的);
NSString *documentsPath = [paths objectAtIndex:0]; NSString *filePath =
[documentsPath stringByAppendingPathComponent:@"scaledimage.png"];
return filePath;
-(void) saveOriginalImageToDir :(UIImage*)image
NSString *filePath = [self getOriginalImageDirectoryPath]; if([[NSFileManager defaultManager] fileExistsAtPath:filePath]) [[NSFileManager defaultManager] removeItemAtPath:filePath error:nil]; NSData *data = UIImagePNGRepresentation(image); [data writeToFile:filePath atomically:YES]; data = nil;
【讨论】:
以上是关于来自 UIImageView 的内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章
来自 Foundation 和 CFNetwork 库的内存泄漏