tags:

views:

38

answers:

3

Hello All,

Currently I am using UIView instead of UIImageview due to Memory consumption in large scale images. following is same code I am using.

- (void)drawRect:(CGRect)rect
{
   CGContextRef context = UIGraphicsGetCurrentContext();
   CGContextClearRect(context, rect);
   [myImage drawInRect:rect];
}

-(void) SetImage:(UIImage*) aImage
{
    if(!aImage)
        return;

    if(myImage)
    {
        [myImage release];
        myImage = nil;
    }

    myImage = [[[UIImage alloc]initWithCGImage:aImage.CGImage] retain];
    [self setNeedsDisplay];
} 

This is causing now memory leak of 8 MB ( checked with Instrument ) every time when Update and set the same image again. if I comment

[self setNeedsDisplay];

There is no leak. can anyone help me here if I am doing something wrong. OR can anyone help me to Subclass UIImageview to handle large scale image.

// Calling functions
    -(void) FitToCardStart
    {
        UIImage* temp = ScaleImage([iImageBgView GetImage]);
        [iImageBgView SetImage:temp];
        [temp release];
        temp = nil;

    }

// ScaleImage

UIImage* ScaleImage(UIImage* image) 
{
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];

    int kMaxResolution = 1800; 

    CGImageRef imgRef = image.CGImage;
    CGFloat width = CGImageGetWidth(imgRef);
    CGFloat height = CGImageGetHeight(imgRef);

    CGAffineTransform transform = CGAffineTransformIdentity;

    CGRect bounds = CGRectMake(0, 0, width, height);

    if (width < kMaxResolution || height < kMaxResolution) 
    {
        CGFloat ratio = width/height;
        if (ratio > 1) 
        {
            bounds.size.width = kMaxResolution;
            bounds.size.height = bounds.size.width / ratio;
        }
        else 
        {
            bounds.size.height = kMaxResolution;    
            bounds.size.width = bounds.size.height * ratio;
        }
    }

    CGFloat scaleRatio = bounds.size.width / width;
    CGSize imageSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef));

    UIImageOrientation orient = image.imageOrientation;

    switch(orient) 
    {

        case UIImageOrientationUp: //default
            transform = CGAffineTransformIdentity;
            break;

        default:
            [NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"];
    }

    UIGraphicsBeginImageContext(bounds.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextScaleCTM(context, scaleRatio, -scaleRatio);
    CGContextTranslateCTM(context, 0, -height);

    CGContextConcatCTM(context, transform);
    CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef);
    UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext();
    UIImage* temp = [[[UIImage alloc] initWithCGImage:imageCopy.CGImage] retain];
    CGImageRelease(imgRef);
    CGContextRelease(context);  

    [pool release];

    return temp;
} 

Thanks,

Sagar

+1  A: 
myImage = [[[UIImage alloc]initWithCGImage:aImage.CGImage] retain];

There's redundant retain in this line - as you're allocating new UIIMage object (use +alloc) method you don't need to extra retain it.

Edit: ScaleImage method has the same problem with redundant retain:

// remove extra retain here
UIImage* temp = [[[UIImage alloc] initWithCGImage:imageCopy.CGImage] retain]; 
// should be
UIImage* temp = [[UIImage alloc] initWithCGImage:imageCopy.CGImage]; 

And a code-style comment - it is better to indicate in your method names what memory management behavior required for returned objects - as image returned by your method needs to be released method name should contain something from "new", "alloc", "copy", "create"...

Vladimir
+1  A: 

Your problem is this line:

myImage = [[[UIImage alloc]initWithCGImage:aImage.CGImage] retain];

alloc already gives you a retain count of 1, with the additional retain you end up with a retain count of 2 which is too high. Remove the retain and everything will be fine.

DarkDust
Thanks DarkDust for reply I done with this but still having same issue.
Sagar Mane
@Sagar, can you also post code where you create aImage and call SetImage method?
Vladimir
@Vladimir I have updated my post with code.
Sagar Mane
@Sagar see updated answer
Vladimir
A: 

I suggest not creating a new image, but just keeping the aImage instance.

myImage = [aImage retain];

I you absolutely must make it a new instance, you are doing it in a very roundabout way. Copying would be a much better alternative.

myImage = [aImage copy];
Steven XM
@Steven Thanks for reply but still having same issue.
Sagar Mane