Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory allocation and release for UIImage in iPhone?

Tags:

iphone

I am using following code in iPhone to get smaller cropped image as follows:

- (UIImage*) getSmallImage:(UIImage*) img
{
    CGSize size = img.size;
    CGFloat ratio = 0;
    if (size.width < size.height) {
        ratio = 36 / size.width;
    } else {
        ratio = 36 / size.height;
    }
    CGRect rect = CGRectMake(0.0, 0.0, ratio * size.width, ratio * size.height);

    UIGraphicsBeginImageContext(rect.size);
    [img drawInRect:rect];

    UIImage *tempImg = [UIGraphicsGetImageFromCurrentImageContext() retain];

    UIGraphicsEndImageContext();
    return [tempImg autorelease];
}

- (UIImage*)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)rect
{

    //create a context to do our clipping in
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef currentContext = UIGraphicsGetCurrentContext();

    //create a rect with the size we want to crop the image to
    //the X and Y here are zero so we start at the beginning of our
    //newly created context

    CGFloat X = (imageToCrop.size.width - rect.size.width)/2;
    CGFloat Y = (imageToCrop.size.height - rect.size.height)/2;


    CGRect clippedRect = CGRectMake(X, Y, rect.size.width, rect.size.height);
    //CGContextClipToRect( currentContext, clippedRect);



    //create a rect equivalent to the full size of the image
    //offset the rect by the X and Y we want to start the crop
    //from in order to cut off anything before them
    CGRect drawRect = CGRectMake(0,
                                 0,
                                 imageToCrop.size.width,
                                 imageToCrop.size.height);

    CGContextTranslateCTM(currentContext, 0.0, drawRect.size.height);
    CGContextScaleCTM(currentContext, 1.0, -1.0);
    //draw the image to our clipped context using our offset rect
    //CGContextDrawImage(currentContext, drawRect, imageToCrop.CGImage);


    CGImageRef tmp = CGImageCreateWithImageInRect(imageToCrop.CGImage, clippedRect);

    //pull the image from our cropped context
    UIImage *cropped = [UIImage imageWithCGImage:tmp];//UIGraphicsGetImageFromCurrentImageContext();
    CGImageRelease(tmp);
    //pop the context to get back to the default
    UIGraphicsEndImageContext();

    //Note: this is autoreleased*/
    return cropped;
}

I am using following line of code in cellForRowAtIndexPath to update the image of the cell:

cell.img.image = [self imageByCropping:[self getSmallImage:[UIImage imageNamed:@"goal_image.png"]] toRect:CGRectMake(0, 0, 36, 36)];

Now when I add this table view and pop it from navigation controller, I see a memory hike.I see no leaks but memory keeps climbing.

Please note that the images changes for each row and I am creating the controller using lazy initialization that is I create or alloc it whenever I need it.

I saw on internet many people facing the same issue, but very rare good solutions. I have multiple views using the same way and I see almost memory raised to 4MB within 20-25 view transitions.

What is the good solution to resolve this issue.

tnx.

like image 220
rkb Avatar asked Oct 07 '09 05:10

rkb


3 Answers

You can't return from the routine before you EndImageContext:

return UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

Try this:

UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;

You don't need the retains or autoreleases that are commented out.

like image 167
mahboudz Avatar answered Nov 18 '22 10:11

mahboudz


Depending on the size of the images, your use of imageNamed: may be responsible for the memory growth. This isn't necessarily a problem. imageNamed: is meant for use by code that frequently loads the same images and is backed by a cache. There were leaks in it prior to iOS 3.0, but they were fixed and I am not aware of any reasons not to use this API if you want to take advantage of the caching.

You should run your code through Instruments, in particular the Leaks template. Using heapshot analysis, you can pinpoint places in your code that increase the memory footprint when you don't expect them to, even if they are missed by traditional leak analysis. Bill Bumgarner wrote a post discussing the use of heapshot analysis. He uses a Mac OS X application for his example, but the techniques apply equally well to iOS apps.

like image 40
Steve Madsen Avatar answered Nov 18 '22 10:11

Steve Madsen


[UIImage imageNamed:] cause memory leaks because it used internal caching of images.

  • Simple method is to cache the image externally by programmer.
    For that, use -(UIImage*)thumbnailImage:(NSString*)fileName { UIImage *thumbnail = [thumbnailCache objectForKey:fileName]; if (nil == thumbnail) {
    NSString *thumbnailFile = [NSString stringWithFormat:@"%/%@", [[NSBundle mainBundle] pathForResource:fileName ofType:@"png"]]; //dont forget to set correct image type thumbnail = [UIImage imageWithContentsOfFile:thumbnailFile]; [thumbnailCache setObject:thumbnail forKey:fileName]; } return thumbnail; }

    Declare NSMutableDictionary *thumbnailCache; in .h file

    And use can use this function like

    cell.img.image = [self imageByCropping:[self getSmallImage:[self thumbnailImage:@"goal_image"]] toRect:CGRectMake(0, 0, 36, 36)];

  • Clear the application shared cache ie set to nil

I think this will solve ur issue.

like image 1
Naveen Shan Avatar answered Nov 18 '22 10:11

Naveen Shan