客观的内存泄漏ARC与UIImage

时间:2014-08-18 07:15:10

标签: objective-c memory-leaks

Leaks工具抱怨类方法的UIImage中存在内存泄漏。怎么解决这个? enter image description here

以下是导致内存泄漏的功能。泄漏发生的地方由&#34表示;此处发生内存泄漏:评论

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;

}

1 个答案:

答案 0 :(得分:1)

此行有潜在泄漏:

// 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];

试试这个:

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

CGImageRelease(quartzImage);