Leaks工具抱怨类方法的UIImage中存在内存泄漏。怎么解决这个?
以下是导致内存泄漏的功能。泄漏发生的地方由&#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;
}
答案 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);