Connection to assetsd was interrupted or assetsd died (with memory warnings)

USERX2DX picture USERX2DX · May 9, 2015 · Viewed 7.3k times · Source

We are trying to let users import picture from their albums(UIImagePickerController) and also we are scaling/resizing down images that are greater than 8 megapixels(iPhone standard).

But every time the app crashes with Connection to assetsd was interrupted or assetsd died and Received memory warning warnings after or before importing picture.At times Received memory warning warning pops up when still looking for picture to import in UIImagePickerController.

Specially on iPhone 4S this is worse, please help us in optimising our code so that it runs without warnings and crashes on older devices like iPhone 4S or iPad 2.

Let us know if we are doing anything wrong in scaling/resizing down image using CoreGraphics.(Because this is where huge memory is used).

 - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
    {
        UIImage *selectedImage=[info objectForKey:UIImagePickerControllerOriginalImage];
        if(UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone)
        {
            [picker dismissViewControllerAnimated:YES completion:nil];
        }
        else
        {
            [popoverController dismissPopoverAnimated:YES];
            [self popoverControllerDidDismissPopover:popoverController];
        }

        // COMPRESSING IMAGE
        NSData   *selectedImageData=UIImageJPEGRepresentation(selectedImage, 0.1);
        UIImage *selectedImageFromData=[UIImage imageWithData:selectedImageData];

        // IMAGE ASPECT RATIO
        CGFloat originalWidth=selectedImageFromData.size.width;
        CGFloat originalHeight=selectedImageFromData.size.height;
        CGFloat myWidth=2048;
        CGFloat myHeight=2048;
        CGFloat widthRatio=myWidth/originalWidth;
        CGFloat heightRatio=myHeight/originalHeight;
        CGFloat dynamicWidth=heightRatio*originalWidth;
        CGFloat dynamicHeight=widthRatio*originalHeight;


        //SCALING UIIMAGE MORE THAN 8 MEGAPIXELS
        if (((selectedImageFromData.size.width>3264) && (selectedImageFromData.size.height>2448)) || ((selectedImageFromData.size.height>3264) && (selectedImageFromData.size.width>2448)))
        {



             // DATA FROM UIIMAGE TO CORE GRAPHICS
             CGImageRef CoreGraphicsImage=selectedImageFromData.CGImage;
            CGColorSpaceRef colorSpace = CGImageGetColorSpace(CoreGraphicsImage);
            CGBitmapInfo bitmapInfo=CGImageGetBitmapInfo(CoreGraphicsImage);
            CGImageGetBitsPerComponent(CoreGraphicsImage);


            // RESIZING WIDTH OF THE IMAGE
            if (originalWidth>originalHeight)
            {


            CGContextRef context=CGBitmapContextCreate(NULL, myWidth, dynamicHeight, CGImageGetBitsPerComponent(CoreGraphicsImage), CGImageGetBytesPerRow(CoreGraphicsImage), colorSpace, bitmapInfo);


            CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
            CGContextDrawImage(context, CGRectMake(0, 0, myWidth, dynamicHeight), CoreGraphicsImage);
            CGImageRef CGscaledImage=CGBitmapContextCreateImage(context);
                UIImage *CGLastimage = [UIImage imageWithCGImage: CGscaledImage];
                NSLog(@"%f",CGLastimage.size.width);
                NSLog(@"%f",CGLastimage.size.height);

                VisualEffectImageVIew.image=CGLastimage;
                BackgroundImageView.image=CGLastimage;
                ForegroundImageView.image=CGLastimage;
            }


            //RESIZING HEIGHT OF THE IMAGE
            if (originalHeight>originalWidth)
            {
                CGContextRef context=CGBitmapContextCreate(NULL, dynamicWidth, myHeight, CGImageGetBitsPerComponent(CoreGraphicsImage), CGImageGetBytesPerRow(CoreGraphicsImage), colorSpace, bitmapInfo);


                CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
                CGContextDrawImage(context, CGRectMake(0, 0, dynamicWidth, myHeight), CoreGraphicsImage);
                CGImageRef CGscaledImage=CGBitmapContextCreateImage(context);
                UIImage *CGLastimage = [UIImage imageWithCGImage: CGscaledImage];

                NSLog(@"%f",CGLastimage.size.width);
                NSLog(@"%f",CGLastimage.size.height);

                VisualEffectImageVIew.image=CGLastimage;
                BackgroundImageView.image=CGLastimage;
                ForegroundImageView.image=CGLastimage;

            }


        }
        else
        {
            NSLog(@" HEIGHT %f",selectedImageFromData.size.height);
            NSLog(@" WIDTH %f",selectedImageFromData.size.width);

        VisualEffectImageVIew.image=selectedImageFromData;
        BackgroundImageView.image=selectedImageFromData;
        ForegroundImageView.image=selectedImageFromData;
        }


    }

Memory Report

when scrolling in UIImagePickerController

http://i.stack.imgur.com/qxx62.png

when scaling/resizing UIImage

http://i.stack.imgur.com/ELCA6.png

Answer

xaphod picture xaphod · May 26, 2015

Two points.

First, you are not releasing the objects you create -- you are leaking huge amounts of memory. Regardless of whether you are using ARC, you must call CGContextRelease or CGImageRelease as appropriate for every CGCreate call.

Second, if you just want to resize, using coregraphics is overkill, use UIKit instead. In the code I use below, note the use of @autorelease to ensure that objects are cleaned up by ARC as soon as the context ends

- (UIImage *)fitImage:(UIImage *)image scaledToFillSize:(CGSize)size {
    // do not upscale

    @autoreleasepool {
        if( image.size.width <= size.width && image.size.height <= size.height )
            return image;

        CGFloat scale = MIN(size.width/image.size.width, size.height/image.size.height);
        CGFloat width = image.size.width * scale;
        CGFloat height = image.size.height * scale;

        CGRect imageRect;
        // center image
        if( scale != 1.0 ) { // avoid divide by zero?
            if( size.width/image.size.width < size.height/image.size.height ) {
                // height needs to be centered
                imageRect = CGRectMake(0, (size.height-height)/2, width, height);
            } else {
                // width needs to be centered
                imageRect = CGRectMake((size.width-width)/2, 0, width, height);
            }
        }

        UIGraphicsBeginImageContextWithOptions(size, YES, 0);
        [[UIColor CollageBorderUIColor] setFill]; // otherwise it's ugly black fill
        UIRectFill(CGRectMake(0, 0, size.width, size.height));
        [image drawInRect:imageRect];
        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return newImage;
    }
}