deltaaruna
deltaaruna

Reputation: 538

objective c memory leak ARC with UIImage

Leaks tool is complaining a memory leak in UIImage of a class method. How to solve this one? enter image description here

Here are the functions that cause the memory leak. The places where the leaks are occurring are shown by "memory leak occurs here.: comment

1
`+(UIImage *) bubbleWithImage: (UIImage *) bubbleImage withColor: (UIColor *) color {

// Get a CGImageRef so we can use CoreGraphics
CGImageRef image = bubbleImage.CGImage;

CGFloat width = CGImageGetWidth(image);
CGFloat height = CGImageGetHeight(image);

// Create a new bitmap context i.e. a buffer to store the pixel data
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

size_t bitsPerComponent = 8;
size_t bytesPerPixel    = 4;
size_t bytesPerRow      = (width * bitsPerComponent * bytesPerPixel + 7) / 8; // As per the header file for CGBitmapContextCreate
size_t dataSize         = bytesPerRow * height;

// Allocate some memory to store the pixels
unsigned char *data = malloc(dataSize);
memset(data, 0, dataSize);

// Create the context
CGContextRef context = CGBitmapContextCreate(data, width, height,
                                             bitsPerComponent, bytesPerRow, colorSpace,
                                             kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

CGColorSpaceRelease(colorSpace);

// Draw the image onto the context
CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);

// Get the components of our input color
const CGFloat * colors = CGColorGetComponents(color.CGColor);

// Change the pixels which have alpha > 0 to our new color
for (int i  = 0 ; i < width * height * 4 ; i+=4)
{
    // If alpha is not zero
    if (data[i+3] != 0) {
        data[i] = (char) (colors[0] * 255);
        data[i + 1] = (char) (colors[1] * 255);
        data[i + 2] = (char) (colors[2] * 255);
    }
}

// Write from the context to our new image
// Make sur to copy across the orientation and scale so the bubbles render
// properly on a retina screen
//****memory leak occurs here.
UIImage * newImage = [[UIImage imageWithCGImage:CGBitmapContextCreateImage(context)
                                          scale:bubbleImage.scale
                                    orientation:bubbleImage.imageOrientation] stretchableImageWithLeftCapWidth:bubbleImage.leftCapWidth
                                                                                                         topCapHeight:bubbleImage.topCapHeight];
// Free up the memory we used
CGContextRelease(context);
free(data);
//CGImageRelease(image);

return newImage;

} `
2

-(void) setMessage: (id<PMessage, PMessageLayout>) message {
// Set the message for later use
_message = message;

// Update the image
UIImage * image = (message.isMine) ? _meBubbleImage : _replyBubbleImage;

// Set the bubble to be the correct color
if (message.color || [message.color isEqualToString:@""]) {
    message.color = @"0.098039 0.784313 0.674509 1";
}
//**memory leak occurs here.
bubbleImageView.image = [BMessageCell bubbleWithImage:image withColor:[BMessage stringToColor:message.color]];
/*
 * default colour is 0.098039 0.784313 0.674509 1
 * sender colour is  0.741176 0.941176 0.909803 1
 * light green   is  0.925490 0.976470 0.784313 1
 */
//build1.5 [check sender]
if (message.isMine) {
    bubbleImageView.image = [BMessageCell bubbleWithImage:image withColor:[BMessage stringToColor:@"0.925490 0.976470 0.784313 1"]];
}else{
    bubbleImageView.image = [BMessageCell bubbleWithImage:image withColor:[BMessage stringToColor:@"0.741176 0.941176 0.909803 1"]];
}

// If the image has an image URL
_profilePicture.hidden = YES;
//[[AsyncImageLoader sharedLoader] cancelLoadingImagesForTarget:_profilePicture];

if (message.user) {
    _profilePicture.hidden = NO;
    _profilePicture.image = message.user.picture;
    NSString *imageURL = [BThreadsViewController getUserImageForEmail:message.user.email];
    ProfilePicManager *mgr = [ProfilePicManager getProfilePicManagerInstance];
    UIImage *savedImage = [mgr retrieveFromDictionary:imageURL];
    if (savedImage) {
        _profilePicture.image = savedImage;
    } else {
        //dwonload the image asyncronously
        [[[AsyncImageDownloader alloc] initWithMediaURL:imageURL successBlock:^(UIImage *image)  {
            _profilePicture.image = image;
            [mgr addToDictionary:imageURL image:image];
        } failBlock:^(NSError *error) {
            NSLog(@"Failed to download image due to %@!", error);
        }] startDownload];
    }
}

NSDateFormatter * dateFormatter = [[NSDateFormatter alloc] init];

NSTimeInterval interval = fabsf([_message.date timeIntervalSinceNow]);
// More than a day ago
if (interval > 3600 * 24) {
    // More than a year ago
    if (interval > 3600 * 24 * 365) {
        [dateFormatter setDateFormat:@"MM/yy"];
    }
    else {
        [dateFormatter setDateFormat:@"dd MMM"];
    }
}
else {
    [dateFormatter setDateFormat:@"HH:mm"];
}

// Add the correct date
_timeLabel.text = [dateFormatter stringFromDate:_message.date];;

}
3

-(void) setMessage: (id<PMessage, PMessageLayout>) message {
//**memory leak occurs here.
[super setMessage:message];

textView.text = message.text;
textView.font = [BMessage fontWithName:message.fontName size:message.fontSize.floatValue];
@try {
    //textView.textColor = [UIColor colorWithCGColor:newcolor.CGColor];
    textView.textColor = [BMessage stringToColor:message.textColor];
}
@catch (NSException *exception) {
    textView.textColor = [UIColor blackColor];
}

}
4

- (UITableViewCell *)tableView:(UITableView *)tableView_ cellForRowAtIndexPath:(NSIndexPath *)indexPath {
id<PMessage, PMessageLayout> message;
if (indexPath.row < [self messages].count) {
    message = [self messages][indexPath.row];
} else {
    message = NULL;
}

UITableViewCell<BMessageDelegate> * messageCell;
if (message) {
    if (message.type.intValue == bMessageTypeText) {
        messageCell = [tableView_ dequeueReusableCellWithIdentifier:bTextMessageCell];
    }
    else if (message.type.intValue == bMessageTypeImage) {
        messageCell = [tableView_ dequeueReusableCellWithIdentifier:bImageMessageCell];
    }
    else if (message.type.intValue == bMessageTypeLocation) {
        messageCell = [tableView_ dequeueReusableCellWithIdentifier:bLocationCell];
    }
    else if (message.type.intValue == bMessageTypeAudio) {
        messageCell = [tableView_ dequeueReusableCellWithIdentifier:bAudioMessageCell];
        if ([messageCell isKindOfClass:[BAudioMessageCell class]]) {
            BAudioMessageCell *audioCell = (BAudioMessageCell*)messageCell;
            //build1.5 [set prg color]
            [audioCell.progressView setTintColor:[UIColor redColor]];
            [audioCell.progressView setBackgroundColor:[UIColor whiteColor]];


            audioCell.delegate = self;
        } else {
            messageCell = [[BAudioMessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:bAudioMessageCell];
            BAudioMessageCell *audioCell = (BAudioMessageCell*)messageCell;
            //build1.5 [set prg color]
            [audioCell.progressView setTintColor:[UIColor redColor]];
            [audioCell.progressView setBackgroundColor:[UIColor whiteColor]];

        }
    }
    [((id<BMessageDelegate>)messageCell) makeDiliveredButtonVisible];
} else {
    NSString *CellIdentifier = NULL;
    if (isUpLoadingAudio) {
        CellIdentifier = @"dummyCellAudio";
    } else if(isUpLoadingImage){
        CellIdentifier = @"dummyCellImage";
    }

    UITableViewCell<DummyView> *cell = NULL;
    if (isUpLoadingImage) {
        cell = [[ImageDummyCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    } else if (isUpLoadingAudio) {
        cell = [tableView_ dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            cell = [[AudioDummyCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
        }
    }
    [(((id<DummyView>)cell)) configureMsgCell];
    uploadProgressView = [((id<DummyView>)cell) uPView];

    return cell;
}

if (indexPath.row < [self messages].count) {
    //**memory leak occurs here.
    [messageCell setMessage:message];
}
NSLog(@"row %d",indexPath.row);

return messageCell;

}

Upvotes: 0

Views: 392

Answers (1)

Casey
Casey

Reputation: 103

This line has a potential leak:

// Write from the context to our new image
// Make sur to copy across the orientation and scale so the bubbles render
// properly on a retina screen
//****memory leak occurs here.
UIImage * newImage = [[UIImage imageWithCGImage:CGBitmapContextCreateImage(context)
                                          scale:bubbleImage.scale
                                    orientation:bubbleImage.imageOrientation] stretchableImageWithLeftCapWidth:bubbleImage.leftCapWidth
                                                                                                         topCapHeight:bubbleImage.topCapHeight];

Try this one instead:

CGImageRef quartzImage = CGBitmapContextCreateImage(context);
UIImage * newImage = [[UIImage imageWithCGImage:quartzImage
                                              scale:bubbleImage.scale
                                        orientation:bubbleImage.imageOrientation] stretchableImageWithLeftCapWidth:bubbleImage.leftCapWidth
                                                                                                             topCapHeight:bubbleImage.topCapHeight];

CGImageRelease(quartzImage);

Upvotes: 1

Related Questions