内存警告UIImagepickerController IOS 7

10

有人能帮我解决这个问题吗?我对Objective C和iOS还不太熟悉。我一直在努力解决这个问题,但是我无法弄清楚如何解决它。我的应用程序非常简单,只需要启动相机拍照并通过电子邮件将它们发送到我们的服务器。这段代码在iOS6中完全正常。

当我拍照时,我的内存会随着每次截屏而增加,并且我会收到“接收到内存警告”的提示,最终出现“因内存压力终止”的错误。

-(void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{

[self.popoverController2 dismissPopoverAnimated:true];
NSString *mediaType = [info
                       objectForKey:UIImagePickerControllerMediaType];

if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {
    _image = [info
                      objectForKey:UIImagePickerControllerOriginalImage];

   _image = [self fixrotation:_image]; //<----- increased memory when UIImageWriteToSavedPhotosAlbum is uncommented IF is comment it doesn't increased memory but after some pictures I start to get "Received Memory Warning" message until the app Crash.

    if (_newMedia){
       UIImageWriteToSavedPhotosAlbum(_image,
                                       self,@selector(image:finishedSavingWithError:contextInfo:),
                                       nil);
    [self dismissViewControllerAnimated:NO completion:nil];
    [self performSegueWithIdentifier:@"SeleccionadoCameraR" sender:self];


    }else{
        [self performSegueWithIdentifier:@"SeleccionadoCameraR" sender:self];

    }

}

}

- (UIImage *)fixrotation:(UIImage *)image{


if (image.imageOrientation == UIImageOrientationUp) return image;
CGAffineTransform transform = CGAffineTransformIdentity;

switch (image.imageOrientation) {
    case UIImageOrientationDown:
    case UIImageOrientationDownMirrored:
        transform = CGAffineTransformTranslate(transform, image.size.width, image.size.height);
        transform = CGAffineTransformRotate(transform, M_PI);
        break;

    case UIImageOrientationLeft:
    case UIImageOrientationLeftMirrored:
        transform = CGAffineTransformTranslate(transform, image.size.width, 0);
        transform = CGAffineTransformRotate(transform, M_PI_2);
        break;

    case UIImageOrientationRight:
    case UIImageOrientationRightMirrored:
        transform = CGAffineTransformTranslate(transform, 0, image.size.height);
        transform = CGAffineTransformRotate(transform, -M_PI_2);
        break;
    case UIImageOrientationUp:
    case UIImageOrientationUpMirrored:
        break;
}

switch (image.imageOrientation) {
    case UIImageOrientationUpMirrored:
    case UIImageOrientationDownMirrored:
        transform = CGAffineTransformTranslate(transform, image.size.width, 0);
        transform = CGAffineTransformScale(transform, -1, 1);
        break;

    case UIImageOrientationLeftMirrored:
    case UIImageOrientationRightMirrored:
        transform = CGAffineTransformTranslate(transform, image.size.height, 0);
        transform = CGAffineTransformScale(transform, -1, 1);
        break;
    case UIImageOrientationUp:
    case UIImageOrientationDown:
    case UIImageOrientationLeft:
    case UIImageOrientationRight:
        break;
}

// Now we draw the underlying CGImage into a new context, applying the transform
// calculated above.
CGContextRef ctx = CGBitmapContextCreate(NULL, image.size.width, image.size.height,
                                         CGImageGetBitsPerComponent(image.CGImage), 0,
                                         CGImageGetColorSpace(image.CGImage),
                                         CGImageGetBitmapInfo(image.CGImage));


CGContextConcatCTM(ctx, transform);
switch (image.imageOrientation) {
    case UIImageOrientationLeft:
    case UIImageOrientationLeftMirrored:
    case UIImageOrientationRight:
    case UIImageOrientationRightMirrored:
        // Grr...
        CGContextDrawImage(ctx, CGRectMake(0,0,image.size.height,image.size.width), image.CGImage);
        break;

    default:
        CGContextDrawImage(ctx, CGRectMake(0,0,image.size.width,image.size.height), image.CGImage); //when I use instruments it shows that My VM is because of this 
        break;
}

// And now we just create a new UIImage from the drawing context
CGImageRef cgimg = CGBitmapContextCreateImage(ctx);//also this line in Instruments
UIImage *img = [UIImage imageWithCGImage:cgimg];


CGContextRelease(ctx);
CGImageRelease(cgimg);


return img;


 }

可能是内存管理问题。感谢您的帮助。


运行静态分析器以查看是否有任何警告。然后在Instruments中运行应用程序,查找任何泄漏和保留循环。 - rmaddy
3个回答

7

你的fixRotation方法已经走在正确的轨道上了,不过你还应该调整图片大小。否则,这张图片将非常大,大约30 MB(取决于设备)。

请查看这篇博客文章,了解如何正确地调整图片大小。具体而言,你需要的是下面这些UIImage类别文件:

UIImage+Resize.h

UIImage+Resize.m

最好还要在后台线程上执行此操作。可以像这样实现:

- (void)imagePickerController:(UIImagePickerController *)imagePicker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    // Dismiss the image picker first to free its memory
    [self dismissViewControllerAnimated:YES completion:nil];

    UIImage *originalImage = info[UIImagePickerControllerOriginalImage];

    if (!originalImage)
        return;

    // Optionally set a placeholder image here while resizing happens in background

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        // Set desired maximum height and calculate width
        CGFloat height = 640.0f;  // or whatever you need
        CGFloat width = (height / originalImage.size.height) * originalImage.size.width;

        // Resize the image
        UIImage * image = [originalImage resizedImage:CGSizeMake(width, height) interpolationQuality:kCGInterpolationDefault];

        // Optionally save the image here...

        dispatch_async(dispatch_get_main_queue(), ^{
            // ... Set / use the image here...
        });           
    });
}

我已经调整了大小,内存增加减少了,但它仍然以稍微慢一些的速度增加,直到我的应用程序崩溃,不知何故,我需要清理内存。 - cesar trujillo cetina
首先,我使用相同的类和方法创建了一个新的iOS7项目,最后将图像调整为640 x 480和480 x 640,然后应用了fixRotation方法。我的内存一次性增加了,但对于其他照片却没有增加。 - cesar trujillo cetina
@cesartrujillocetina,你能展示一下你的最终工作代码吗?我也遇到了同样的问题。 - Danpe

4

UIImageWriteToSavedPhotosAlbum 方法在 iOS7 上使用了 30M+ 的内存。这与您的 resize 或 fixrotation 方法无关。


我也有同样的问题.. 有人有解决方案吗? - Sabareesh
是的,每次我调用UIImageWriteToSavedPhotosAlbum时,我的应用程序都会收到内存警告!显然会崩溃! - Siddhartha Moraes

1
我通过JRG-Developer的答案进行了修复,稍作修改: 我使用分类来修正图像方向,并在呈现之前将其缩小, 完成后,我调用Weak Self将此已缩放和修复的图像分配给我的imageView。
-(void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{    
    UIImage *lvImage = [info objectForKey:UIImagePickerControllerOriginalImage];
    //CGSize pickedImageSize = lvImage.size;
    if (postHandler == nil)
    {
        postHandler = [[PostHandler alloc] init];
    }

    //_postItemImageView.image = lvImage;
    //postHandler.wholeScreenImage = lvImage;// to proceed editing, cropping, tagging ...
    //_postItemImageView.image = postHandler.wholeScreenImage; set in viewWillAppear
    __weak PostPrepareViewController *weakSelf = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
    {

        // Resize the image
        UIImage * scaledImage = [[lvImage imageByScalingAndCroppingForSize:_postItemImageView.frame.size] fixOrientation];
        // Optionally save the image here...
        //CGSize scaledimageSize = scaledImage.size;
        dispatch_async(dispatch_get_main_queue(), ^
        {
            postHandler.wholeScreenImage = scaledImage;
            [weakSelf didScaleDownImage];
        });           
    });


    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
    {
        [self.popOver dismissPopoverAnimated:YES];
    }
    else
    {
        [self dismissViewControllerAnimated:YES completion:nil];
    }
}

和更低:

-(void) didScaleDownImage
{
   _postItemImageView.image = postHandler.wholeScreenImage;
}

缩放代码取自网络:

-(UIImage *)imageByScalingAndCroppingForSize:(CGSize)targetSize
{
    UIImage *sourceImage = self;
    UIImage *newImage = nil;
    CGSize imageSize = sourceImage.size;
    CGFloat width = imageSize.width;
    CGFloat height = imageSize.height;
    CGFloat targetWidth = targetSize.width;
    CGFloat targetHeight = targetSize.height;
    CGFloat scaleFactor = 0.0;
    CGFloat scaledWidth = targetWidth;
    CGFloat scaledHeight = targetHeight;
    CGPoint thumbnailPoint = CGPointMake(0.0,0.0);

    if (CGSizeEqualToSize(imageSize, targetSize) == NO)
    {
        CGFloat widthFactor = targetWidth / width;
        CGFloat heightFactor = targetHeight / height;

        if (widthFactor > heightFactor)
        {
            scaleFactor = widthFactor; // scale to fit height
        }
        else
        {
            scaleFactor = heightFactor; // scale to fit width
        }

        scaledWidth  = width * scaleFactor;
        scaledHeight = height * scaleFactor;

        // center the image
        if (widthFactor > heightFactor)
        {
            thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
        }
        else
        {
            if (widthFactor < heightFactor)
            {
                thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
            }
        }
    }

    UIGraphicsBeginImageContext(targetSize); // this will crop
    //UIGraphicsBeginImageContextWithOptions(targetSize, 1.0, 0.0);

    CGRect thumbnailRect = CGRectZero;
    thumbnailRect.origin = thumbnailPoint;
    thumbnailRect.size.width  = scaledWidth;
    thumbnailRect.size.height = scaledHeight;

    [sourceImage drawInRect:thumbnailRect];

    newImage = UIGraphicsGetImageFromCurrentImageContext();

    if(newImage == nil)
    {
        NSLog(@"could not scale image");
    }

    //pop the context to get back to the default
    UIGraphicsEndImageContext();

    return newImage;
}

同时,用于更改(修复)图像方向的代码也是从网络上获取的:

- (UIImage *)fixOrientation
{    // No-op if the orientation is already correct
    if (self.imageOrientation == UIImageOrientationUp) return self;

    // We need to calculate the proper transformation to make the image upright.
    // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
    CGAffineTransform transform = CGAffineTransformIdentity;

    switch (self.imageOrientation) {
        case UIImageOrientationDown:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height);
            transform = CGAffineTransformRotate(transform, M_PI);
            break;

        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
            transform = CGAffineTransformTranslate(transform, self.size.width, 0);
            transform = CGAffineTransformRotate(transform, M_PI_2);
            break;

        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform, 0, self.size.height);
            transform = CGAffineTransformRotate(transform, -M_PI_2);
            break;

        default:
            break;
    }

    switch (self.imageOrientation) {
        case UIImageOrientationUpMirrored:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform, self.size.width, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;

        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform, self.size.height, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;

        default:
            break;
    }

    // Now we draw the underlying CGImage into a new context, applying the transform
    // calculated above.
    CGContextRef ctx = CGBitmapContextCreate(NULL, self.size.width, self.size.height,
                                             CGImageGetBitsPerComponent(self.CGImage), 0,
                                             CGImageGetColorSpace(self.CGImage),
                                             CGImageGetBitmapInfo(self.CGImage));
    CGContextConcatCTM(ctx, transform);
    switch (self.imageOrientation) {
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            // Grr...
            CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage);
            break;

        default:
            CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage);
            break;
    }

    // And now we just create a new UIImage from the drawing context
    CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
    CGContextRelease(ctx);
    UIImage *img = [UIImage imageWithCGImage:cgimg];

    CGImageRelease(cgimg);
   //
    return img;
}

请不要因为某些东西看起来很傻而进行减分,我现在是初学者。
对于下面的回答-这就是为什么最好缩小图像-以减少使用的内存,而不是简单地将大的4MB图像保存到磁盘。在一开始我也有内存问题-每张照片都会占用30Mb-我不得不一个一个地拍2张照片...现在它运行得很好,很顺畅。修复方向是可选的,但我仍然建议缩小照片-将其调整为较小的大小。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接