Memory allocation and release for UIImage on iPhone?

I use the following code on an iPhone to get a reduced crop 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 use the following line of code in cellForRowAtIndexPath to update the cell image:

 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 out of the navigation controller, I see a burst with memory. I do not see leaks, but memory continues to rise.

Note that the images change for each row, and I create the controller using the lazy initialization, which I create or highlight when I need it.

I have seen on the Internet a lot of people facing the same problem, but very rare good solutions. I have several views using the same path, and I see that almost the memory has been raised to 4 MB for 20-25 views.

What a good solution to solve this problem.

Tpx.

+6
iphone
source share
5 answers

You cannot return from a routine before EndImageContext:

 return UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); 

Try the following:

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

You do not need saved or auto-implementers that are commented out.

+1
source share

[UIImage imageNamed:] causes a memory leak because it uses internal image caching.

  • A simple method is to cache the image from the outside by the programmer.
    To do this, 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; }
    -(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 usage can use this function, for example

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

  • Clear the general application cache, i.e. set to nil

I think this will solve ur problem.

+1
source share

Depending on the size of the images, the use of imageNamed: may depend on memory growth. This is not necessarily a problem. imageNamed: designed for use by code that often downloads the same images and is backed up by a cache. It had leaks before iOS 3.0, but they were fixed, and I don’t know any reason not to use this API if you want to use caching.

You must run your code through the "Tools", in particular the "Leaks" template. Using heap analysis, you can identify places in the code that increase memory when you do not expect them, even if they are overlooked due to traditional leak analysis. Bill Bumgarner wrote a post discussing the use of heap analysis. He uses the Mac OS X application for his example, but the methods apply equally well to iOS applications.

+1
source share

Does not solve the problem, but may make it unrelated to the problem: cache your thumbnails. At 36 x 36 they will be very small for storage in memory. It should also provide increased performance, as the graphics work is pretty intense.

0
source share

Instead of using autorelease to manage memory (which, as far as I know, does not have or does not guarantee that when the memory is released, it just ends up) will split your line of usage code into three parts and manage the memory yourself. At best, this may be all that is needed to fix memory leaks. At the very least, a tool like Tools can take it from there and show you where the memory leaks come from.

In addition, [UIImage imageNamed:] can be costly and auto-implement an image. You can replace this call with a relatively simple image caching mechanism that can reuse frequently requested images and improve download performance.

-one
source share

All Articles