【问题标题】:objective c memory leak ARC with UIImage带有UIImage的目标c内存泄漏ARC
【发布时间】:2014-08-18 07:15:10
【问题描述】:

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

以下是导致内存泄漏的函数。发生泄漏的地方显示为“这里发生内存泄漏。: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;

}

【问题讨论】:

    标签: objective-c memory-leaks


    【解决方案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);
    

    【讨论】:

    • 谢谢它就像一个魅力:)。能不能给我一个小小的解释?
    • 每次调用CGBitmapContextCreateImage都会增加你的retain count,因为CGImageRef是一个C类型的对象,直到你调用release才会释放内存。 *ARC 不管理 C 类型。
    猜你喜欢
    • 2014-06-15
    • 2015-06-28
    • 1970-01-01
    • 2012-04-03
    • 2012-09-14
    • 1970-01-01
    • 2013-05-23
    • 2012-10-05
    • 1970-01-01
    相关资源
    最近更新 更多