开发者

Memory allocation and release for UIImage in iPhone?

开发者 https://www.devze.com 2022-12-08 01:37 出处:网络
I am using following code in iPhone to get smaller cropped image as follows: - (UIImage*) getSmallImage:(UIImage*) img

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-2开发者_StackOverflow社区5 view transitions.

What is the good solution to resolve this issue.

tnx.


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.


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.


[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.


Doesn't solve the problem, but might make it a non-issue: Cache your thumbnails. At 36 x 36 they are going to be very small to hold in memory. This should also provide a performance boost as the graphic work is pretty intensive.


Instead of using autorelease to manage the memory (which, as far as I know, has little or no guarantees about when memory will be released, just that it will eventually) split your use-case line of code into three parts and manage the memory yourself. At best that may be all that is necessary to resolve the memory leaks. At the very least a tool like Instruments will be able to take it from there and show you where possible memory leaks are being generated from.

Also, [UIImage imageNamed:] can be expensive and autoreleases the image. You could replace that call with a relatively simple image caching mechanism that could reuse commonly requested images and get you a performance boost to boot.

0

精彩评论

暂无评论...
验证码 换一张
取 消