iPad应用程序在组合/合并两张图像时因内存警告而崩溃

我正在做image processing时,由于大量使用内存,我的应用程序崩溃。

基本上我的整个应用程序取决于下面的方法,其中用于组合图像的逻辑被用来从bundle中加载图像的另一种方法。

+ (UIImage*)imageByCombiningImages:(UIImage*)firstImage withImage:(UIImage*)secondImage { @autoreleasepool { UIImage *image = nil; CGSize newImageSize = CGSizeMake(MAX(firstImage.size.width, secondImage.size.width), MAX(firstImage.size.height, secondImage.size.height)); if (UIGraphicsBeginImageContextWithOptions != NULL) { UIGraphicsBeginImageContextWithOptions(newImageSize, NO, [[UIScreen mainScreen] scale]); } else { UIGraphicsBeginImageContext(newImageSize); } [firstImage drawAtPoint:CGPointMake(roundf((newImageSize.width-firstImage.size.width)/2), roundf((newImageSize.height-firstImage.size.height)/2))]; firstImage =nil; [secondImage drawAtPoint:CGPointMake(roundf((newImageSize.width-secondImage.size.width)/2), roundf((newImageSize.height-secondImage.size.height)/2))]; secondImage=nil; image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; } } - (UIImage*) getImage:(NSString*)imagename { NSString *fileName = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:imagename]; UIImage *image = [UIImage imageWithContentsOfFile:fileName]; return image; } 

上述方法被多次从以下方法调用

 - (void) applyMaterialWithValue:(NSDictionary*)dict { @synchronized(self) { NSString *materialName = [dict valueForKey:@"material"]; NSString *optionName = [dict valueForKey:@"option"]; //NSString *preset_Name = [dict valueForKey:@"preset"]; NSString *name = [dict valueForKey:@"name"]; if([[GlobalIntVariable getCMFScheme] isEqualToString:@"preset1"]) { if(!isMetalPressed) { [GlobalIntVariable setCurrentMaterialName:@"Preset 1 Metal Plating"]; } if(!isLeatherPressed) { [GlobalIntVariable setCurrentPresetName:@"preset1"]; } } if([[GlobalIntVariable getCMFScheme] isEqualToString:@"preset2"]) { if(!isMetalPressed) { [GlobalIntVariable setCurrentMaterialName:@"Preset 2 Metal Plating"]; } if(!isLeatherPressed) { [GlobalIntVariable setCurrentPresetName:@"preset2"]; } } if ([materialName isEqualToString:AREAD4METALCOMPONENET ]|| [materialName isEqualToString:AREA8METALCOMPONENET]) { [GlobalIntVariable setCurrentMaterialName:name]; } if([optionName isEqualToString:OPTION0]) { @autoreleasepool { UIImage *presetImg1L1Standard = [APP_DEL getImage:[dict valueForKey:@"image1L1Standard"]]; imgView1Layout1Standard.image = [ImageOperations imageByCombiningImages:imgView1Layout1Standard.image withImage:presetImg1L1Standard]; imgView1Layout1StandardPSUOn.image = [ImageOperations imageByCombiningImages:imgView1Layout1StandardPSUOn.image withImage:presetImg1L1Standard]; presetImg1L1Standard=nil; UIImage *presetImg1L1Premium = [APP_DEL getImage:[dict valueForKey:@"image1L1Premium"]]; imgView1Layout1Premium.image = [ImageOperations imageByCombiningImages:imgView1Layout1Premium.image withImage:presetImg1L1Premium]; imgView1Layout1PremiumPSUOn.image = [ImageOperations imageByCombiningImages:imgView1Layout1PremiumPSUOn.image withImage:presetImg1L1Premium]; presetImg1L1Premium=nil; UIImage *presetImg1L2Standard = [APP_DEL getImage:[dict valueForKey:@"image1L2Standard"]]; imgView1Layout2Standard.image = [ImageOperations imageByCombiningImages:imgView1Layout2Standard.image withImage:presetImg1L2Standard]; imgView1Layout2StandardPSUOn.image = [ImageOperations imageByCombiningImages:imgView1Layout2StandardPSUOn.image withImage:presetImg1L2Standard]; presetImg1L2Standard=nil; UIImage *presetImg1L2Premium = [APP_DEL getImage:[dict valueForKey:@"image1L2Premium"]]; imgView1Layout2Premium.image = [ImageOperations imageByCombiningImages:imgView1Layout2Premium.image withImage:presetImg1L2Premium]; imgView1Layout2PremiumPSUOn.image = [ImageOperations imageByCombiningImages:imgView1Layout2PremiumPSUOn.image withImage:presetImg1L2Premium]; presetImg1L2Premium=nil; } @autoreleasepool { UIImage *presetImg2L1Standard = [APP_DEL getImage:[dict valueForKey:@"image2L1Standard"]]; imgView2Layout1Standard.image = [ImageOperations imageByCombiningImages:imgView2Layout1Standard.image withImage:presetImg2L1Standard]; imgView2Layout1StandardPSUOn.image = [ImageOperations imageByCombiningImages:imgView2Layout1StandardPSUOn.image withImage:presetImg2L1Standard]; presetImg2L1Standard=nil; UIImage *presetImg2L1Premium = [APP_DEL getImage:[dict valueForKey:@"image2L1Premium"]]; imgView2Layout1Premium.image = [ImageOperations imageByCombiningImages:imgView2Layout1Premium.image withImage:presetImg2L1Premium]; imgView2Layout1PremiumPSUOn.image = [ImageOperations imageByCombiningImages:imgView2Layout1PremiumPSUOn.image withImage:presetImg2L1Premium]; presetImg2L1Premium=nil; UIImage *presetImg2L2Standard = [APP_DEL getImage:[dict valueForKey:@"image2L2Standard"]]; imgView2Layout2Standard.image = [ImageOperations imageByCombiningImages:imgView2Layout2Standard.image withImage:presetImg2L2Standard]; imgView2Layout2StandardPSUOn.image = [ImageOperations imageByCombiningImages:imgView2Layout2StandardPSUOn.image withImage:presetImg2L2Standard]; presetImg2L2Standard=nil; UIImage *presetImg2L2Premium = [APP_DEL getImage:[dict valueForKey:@"image2L2Premium"]]; imgView2Layout2Premium.image = [ImageOperations imageByCombiningImages:imgView2Layout2Premium.image withImage:presetImg2L2Premium]; imgView2Layout2PremiumPSUOn.image = [ImageOperations imageByCombiningImages:imgView2Layout2PremiumPSUOn.image withImage:presetImg2L2Premium]; presetImg2L2Premium=nil; } @autoreleasepool { UIImage *presetImg3L1Standard = [APP_DEL getImage:[dict valueForKey:@"image3L1Standard"]]; imgView3Layout1Standard.image = [ImageOperations imageByCombiningImages:imgView3Layout1Standard.image withImage:presetImg3L1Standard]; imgView3Layout1StandardPSUOn.image = [ImageOperations imageByCombiningImages:imgView3Layout1StandardPSUOn.image withImage:presetImg3L1Standard]; presetImg3L1Standard=nil; UIImage *presetImg3L1Premium = [APP_DEL getImage:[dict valueForKey:@"image3L1Premium"]]; imgView3Layout1Premium.image = [ImageOperations imageByCombiningImages:imgView3Layout1Premium.image withImage:presetImg3L1Premium]; imgView3Layout1PremiumPSUOn.image = [ImageOperations imageByCombiningImages:imgView3Layout1PremiumPSUOn.image withImage:presetImg3L1Premium]; presetImg3L1Premium=nil; UIImage *presetImg3L2Standard = [APP_DEL getImage:[dict valueForKey:@"image3L2Standard"]]; imgView3Layout2Standard.image = [ImageOperations imageByCombiningImages:imgView3Layout2Standard.image withImage:presetImg3L2Standard]; imgView3Layout2StandardPSUOn.image = [ImageOperations imageByCombiningImages:imgView3Layout2StandardPSUOn.image withImage:presetImg3L2Standard]; presetImg3L2Standard=nil; UIImage *presetImg3L2Premium = [APP_DEL getImage:[dict valueForKey:@"image3L2Premium"]]; imgView3Layout2Premium.image = [ImageOperations imageByCombiningImages:imgView3Layout2Premium.image withImage:presetImg3L2Premium]; imgView3Layout2PremiumPSUOn.image = [ImageOperations imageByCombiningImages:imgView3Layout2PremiumPSUOn.image withImage:presetImg3L2Premium]; presetImg3L2Premium=nil; } } @autoreleasepool { UIImage *presetImg4Standard = [APP_DEL getImage:[dict valueForKey:@"image4Standard"]]; mainImageView4.image=[ImageOperations imageByCombiningImages:mainImageView4.image withImage:presetImg4Standard]; presetImg4Standard=nil; UIImage *presetImg5Standard = [APP_DEL getImage:[dict valueForKey:@"image5Standard"]]; mainImageView5.image=[ImageOperations imageByCombiningImages:mainImageView5.image withImage:presetImg5Standard]; presetImg5Standard=nil; } @autoreleasepool { UIImage *presetImg1Detail1 = [APP_DEL getImage:[dict valueForKey:@"image1DetailView1"]]; imgView1Detail.image = [ImageOperations imageByCombiningImages:imgView1Detail.image withImage:presetImg1Detail1]; presetImg1Detail1=nil; UIImage *presetImg2Detail2 = [APP_DEL getImage:[dict valueForKey:@"image2DetailView2"]]; imgView2Detail.image = [ImageOperations imageByCombiningImages:imgView2Detail.image withImage:presetImg2Detail2]; presetImg2Detail2=nil; UIImage *presetImg3Detail3 = [APP_DEL getImage:[dict valueForKey:@"image3DetailView3"]]; imgView3Detail.image = [ImageOperations imageByCombiningImages:imgView3Detail.image withImage:presetImg3Detail3]; presetImg3Detail3=nil; } [self setMaterialReflection]; NSString *strShowIndicator = [dict valueForKey:@"hideIndicator"]; if ([strShowIndicator isEqualToString:@"YES"]) { [appDelegate hideIndicator]; } } } 

问题是,当上述方法称为内存使用超过400 MB&我收到2 – 3次在控制台收到内存警告消息&我的应用程序崩溃后。

在运行时上面的方法在执行内存总是增加,即使你在上面的方法中看到我有零所有的uiimage对象也使用@ autorelese块但内存不释放。

每次以下方法调用后,我都想减less内存。

  • (UIImage *)imageByCombiningImages:(UIImage *)firstImage withImage:(UIImage *)secondImage

在上面的方法中,我将两个图像合并到一个图像中,我的项目中的所有图像的平均大小为2 MB。

我已经减less图像的大小,以2 MB的平均值之前,它是4 MB,如果我降低图像分辨率比应用程序的质量下降&这不是我想要的。

我已经做了谷歌关于它试图find堆栈溢出的解决scheme,但仍然没有什么,所以请指导我通过这个问题。

请提示我如何改进图像合成的方法? 我怎样才能优化以上的方法,以便减less内存使用,我的应用程序可以顺利运行。

我可以build议的一点是,不要每次都从graphics上下文中捕捉图像。

尝试以下步骤:

  1. 将字典传递给方法imageByCombiningImages:
  2. 计算框架
  3. 迭代字典中的所有图像并绘制
  4. 只捕获一次最终的图像。

编辑1:

编辑方法:

  + (UIImage*)imageByCombiningImages:(NSDictionary *)imageDict { UIImage *image = nil; CGSize newImageSize = CGSizeZero; NSArray *allImages = [imageDict allValues]; for (UIImage *image in allImages) { newImageSize = CGSizeMake(MAX(image.size.width, newImageSize.size.width), MAX(image.size.height, newImageSize.size.height)); } if (UIGraphicsBeginImageContextWithOptions != NULL) { UIGraphicsBeginImageContextWithOptions(newImageSize, NO, [[UIScreen mainScreen] scale]); } else { UIGraphicsBeginImageContext(newImageSize); } for (UIImage *image in allImages) { [image drawAtPoint:CGPointMake(roundf((newImageSize.width-image.size.width)/2), roundf((newImageSize.height-image.size.height)/2))]; } image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; } 

编辑2:

当您使用UIGraphicsGetImageFromCurrentImageContext()创build图像时,内部cg栅格数据由核心graphics创build,以创build位图图像。 它会消耗更多的内存。

您可以通过延迟顺序方法调用合并图像来避免内存警告。

编辑3:

修改图像合并方法:

 - (void)imageByCombiningImages:(UIImage*)firstImage withImage:(UIImage*)secondImage { UIImage *image = nil; CGSize newImageSize = CGSizeMake(MAX(firstImage.size.width, secondImage.size.width), MAX(firstImage.size.height, secondImage.size.height)); if (UIGraphicsBeginImageContextWithOptions != NULL) { UIGraphicsBeginImageContextWithOptions(newImageSize, NO, [[UIScreen mainScreen] scale]); } else { UIGraphicsBeginImageContext(newImageSize); } [firstImage drawAtPoint:CGPointMake(roundf((newImageSize.width-firstImage.size.width)/2), roundf((newImageSize.height-firstImage.size.height)/2))]; firstImage =nil; [secondImage drawAtPoint:CGPointMake(roundf((newImageSize.width-secondImage.size.width)/2), roundf((newImageSize.height-secondImage.size.height)/2))]; secondImage=nil; image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); [self performSelector:@selector(merge:) withObject:image afterDelay:1]; // modify the delay which will work out for you } 

添加数组中的所有图像键并调用方法,

 - (void)merge:(UIImage *)image { switch (rowIndex) { case 0: { UIImage *presetImg1L1Standard = [APP_DEL getImage:[dict valueForKey:[imagesArray objectAtIndex:rowIndex]]]; switch (sectionIndex) { case 0: [ImageOperations imageByCombiningImages:imgView1Layout1Standard.image withImage:presetImg1L1Standard]; sectionIndex++; break; case 1: imgView1Layout1Standard.image = image; [ImageOperations imageByCombiningImages:imgView1Layout1StandardPSUOn.image withImage:presetImg1L1Standard]; rowIndex ++; sectionIndex = 0; break; default: break; } } break; case 1: { UIImage *image = [APP_DEL getImage:[dict valueForKey:[imagesArray objectAtIndex:rowIndex]]]; switch (sectionIndex) { case 0: imgView1Layout1StandardPSUOn.image = image; [ImageOperations imageByCombiningImages:imgView1Layout1Premium.image withImage:image]; sectionIndex++; break; case 1: imgView1Layout1Premium.image = image; [ImageOperations imageByCombiningImages:imgView1Layout1Premium.image withImage:presetImg1L1Premium]; rowIndex ++; sectionIndex = 0; break; default: break; } } break; // ................. and so on default: break; } } 

希望这会给你一个想法。

我会尝试在GPU上进行计算,例如使用GPUImage的混合filter之一 。