Память Предупреждение UIImagepickerController IOS 7

Может кто-нибудь помочь мне в этом вопросе, я немного новичок в объектах 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;


 }

возможно, это управление памятью. Я буду благодарен за вашу помощь.

Ответ 1

Вы находитесь на правильном пути с помощью метода fixRotation. Однако вы также должны изменить размер изображения. В противном случае изображение будет огромным, ~ 30 МБ (в зависимости от устройства).

Оформить заказ это сообщение в блоге о том, как правильно изменить размер изображений. В частности, файлы категорий 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...
        });           
    });
}

Ответ 2

UIImageWriteToSavedPhotosAlbum метод использует 30M + память на iOS7.Это не о вашем методе изменения размера или фиксации.

Ответ 3

Я исправил эту проблему с помощью ответа JRG-Developer здесь с небольшими изменениями: Я использую категории для фиксации ориентации изображения и его масштабирования перед представлением и когда это делается, я называю Weak Self, чтобы назначить это масштабированное и фиксированное изображение в мое изображение)

-(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;
}

пожалуйста, не будьте жестокими в том, чтобы ругать, если что-то выглядит фиктивным) I-m junior на данный момент)

Для ответа ниже - это то, что вам лучше масштабировать изображение - чтобы использовать меньше памяти, но не просто сохранить большое изображение 4 МБ на диск. В самом начале у меня также были проблемы с памятью - он ел 30 Мб на фотографию сигл - и мне приходилось снимать по 2 фотографии один за другим... теперь он работает отлично и плавно. Исправление ориентации необязательно, но я бы порекомендовал все равно уменьшить масштаб фотографии - измените ее размер до меньшего размера.