Утечка памяти при загрузке изображения в пользовательскую ячейку в UITableView

В моем приложении для iPhone есть UITableView с настраиваемыми ячейками. Который содержит UILabels и UIImageViews. Но у меня возникает утечка памяти, когда я назначаю изображение представлению изображения. Вот код. Утечка находится в методе cellForRowAtIndexPath: я упомянул процент утечки. Пожалуйста, проверьте код, что здесь пошло не так? Пожалуйста помоги.

        //  UIMenuItemCell.h
            @class UIMenuitemImage;
            @interface UIMenuItemCell : UITableViewCell{
                UILabel *cellItemName;
                UIImageView *cellitemImage;
            }
            @property (nonatomic, retain) UILabel *cellItemName;
            @property (nonatomic, retain) UIImageView *cellitemImage;

        //  UIMenuItemCell.m

        #import "UIMenuItemCell.h"

        @implementation UIMenuItemCell
        @synthesize cellItemName, cellitemImage, cellItemButton, cellItemProgress;

        - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
        {
            self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
            if (self) {
                // Initialization code
        //        cellitemImage = [[UIMenuitemImage alloc]init];
            }
            return self;
        }

        - (void)setSelected:(BOOL)selected animated:(BOOL)animated  
        {
            [super setSelected:selected animated:animated];

            // Configure the view for the selected state
        }

    //  MenuScreenVC.m
    - (UIMenuItemCell *) getCellContentView:(NSString *)cellIdentifier {

    CGRect CellFrame = CGRectMake(0, 0, 150, 60);
    CGRect Label1Frame = CGRectMake(20, 23, 98, 30);
    CGRect imgFrame = CGRectMake(20, 48, 110, 123);
    CGRect btnFrame = CGRectMake(25, 136, 100, 30);
    CGRect progressFrame = CGRectMake(25, 140, 100, 21);

    UILabel *lblTemp;
    UIImageView *itemImg;
    UIButton *itemBtn;
    UIProgressView *itemProgView;

    UIMenuItemCell *cell = [[[UIMenuItemCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];
    cell.frame = CellFrame;

    //Initialize Label with tag 1.  
    lblTemp = [[UILabel alloc] initWithFrame:Label1Frame];
    lblTemp.tag = 1;
    lblTemp.textColor=[UIColor colorWithRed:139.0f/255.0f green:69.0f/255.0f blue:19.0f/255.0f alpha:1.0f];
    lblTemp.textAlignment = UITextAlignmentCenter;
    lblTemp.backgroundColor = [UIColor clearColor];
    lblTemp.font = [UIFont systemFontOfSize:13.0];
    [cell.contentView addSubview:lblTemp];
    [lblTemp release];

    //Initialize ImageView
    itemImg = [[UIImageView alloc]initWithFrame:imgFrame];
    itemImg.tag = 2;
    [cell.contentView addSubview:itemImg];
    [itemImg release];

    //Initialize Button
    itemBtn = [[UIButton alloc]initWithFrame:btnFrame];
    itemBtn.frame = btnFrame;
    itemBtn.tag = 3;
    itemBtn.titleLabel.textColor = [UIColor blueColor];
    itemBtn.titleLabel.font = [UIFont systemFontOfSize:9.0];
    [cell.contentView addSubview:itemBtn];
    [itemBtn release];

    //Initialize ProgressView
    itemProgView = [[CustomProgressView alloc]initWithFrame:progressFrame];
    itemProgView.tag = 4;
    //[cell.contentView addSubview:itemProgView];
    [itemProgView release];

    return cell;
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

    NSString *CellIdentifier = [NSString stringWithFormat:@"Cell%d", indexPath.row];

    UIMenuItemCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if(cell == nil){
        cell = [self getCellContentView:CellIdentifier];

        cell.transform = CGAffineTransformMakeRotation(M_PI_2);
        cell.selectionStyle = UITableViewCellSelectionStyleNone;

        cell.cellItemName = (UILabel *)[cell viewWithTag:1];
        cell.cellitemImage = (UIImageView *)[cell viewWithTag:2];
        cell.cellItemButton = (UIButton *)[cell viewWithTag:3];
        cell.cellItemProgress = (UIProgressView *)[cell viewWithTag:4];

        DataBaseClass *itemObj = [appDelegate.itemArray objectAtIndex:indexPath.row];

        __autoreleasing NSString *imageLocalFilePath = nil;
        if ([[tempitemStatusArray objectAtIndex:indexPath.row] isEqualToString:@"NotAvailable"]) {
            cell.cellItemProgress.hidden = YES;
            cell.cellItemButton.hidden = NO;
            imageLocalFilePath = [NSString stringWithFormat:@"%@",[tempItemLocalNotAvailPath objectAtIndex:indexPath.row]];
            NSString *date = [self changeDateFormat:itemObj.itemReleaseDate];          
            [cell.cellItemButton setTitle:date forState:UIControlStateNormal]; 
            cell.cellItemButton.userInteractionEnabled = NO;
            cell.userInteractionEnabled = NO;
            [cell.cellItemButton removeTarget:nil action:NULL forControlEvents:UIControlEventAllEvents];
            [cell.cellItemButton setBackgroundImage:[UIImage imageNamed:@"not_available_bttn_bck_img"] forState:UIControlStateNormal];
        }else if ([[tempitemStatusArray objectAtIndex:indexPath.row] isEqualToString:@"Available"]){
            cell.cellItemButton.userInteractionEnabled = YES;
            cell.userInteractionEnabled = YES;
            cell.cellItemProgress.hidden = YES;
            [cell.cellItemButton setTitle:@"" forState:UIControlStateNormal];
            [cell.cellItemButton setBackgroundImage:[UIImage imageNamed:@"available_bttn_img_normal"] forState:UIControlStateNormal];
            [cell.cellItemButton setBackgroundImage:[UIImage imageNamed:@"available_bttn_img_pressed"] forState:UIControlStateHighlighted];
            [cell.cellItemButton removeTarget:nil action:NULL forControlEvents:UIControlEventAllEvents];
            [cell.cellItemButton addTarget:self action:@selector(confirmationAlert:) forControlEvents:UIControlEventTouchUpInside];
            imageLocalFilePath = [NSString stringWithFormat:@"%@",[tempItemLocalAvailPath objectAtIndex:indexPath.row]];
        }else if ([[tempitemStatusArray objectAtIndex:indexPath.row] isEqualToString:@"Active"]) {
            cell.cellItemButton.userInteractionEnabled = YES;
            cell.userInteractionEnabled = YES;
            cell.cellItemProgress.hidden = YES;
            [cell.cellItemButton setTitle:@"" forState:UIControlStateNormal];
            [cell.cellItemButton setBackgroundImage:[UIImage imageNamed:@"active_bttn_img_normal"] forState:UIControlStateNormal];
            [cell.cellItemButton removeTarget:nil action:NULL forControlEvents:UIControlEventAllEvents];
            [cell.cellItemButton addTarget:self action:@selector(alert) forControlEvents:UIControlEventTouchUpInside];
            imageLocalFilePath = [NSString stringWithFormat:@"%@",[tempItemLocalAvailPath objectAtIndex:indexPath.row]];
        }else if([[tempitemStatusArray objectAtIndex:indexPath.row] isEqualToString:@"Downloading"]) {
            imageLocalFilePath = [NSString stringWithFormat:@"%@",[tempItemLocalAvailPath objectAtIndex:indexPath.row]];
            [cell.contentView addSubview:myprogressView];
            cell.cellItemButton.hidden = YES;
        }
        if ([imageLocalFilePath isEqualToString:@""]) {
            [cell.cellitemImage setImage:[UIImage imageNamed:@"item01.png"]];
        }else {
            [cell.cellitemImage setImage:[UIImage imageWithContentsOfFile:imageLocalFilePath]];
        }        
        cell.cellItemName.text = [NSString stringWithFormat:@"%@",[tempItemNameArray objectAtIndex:indexPath.row]]; 

        for (UIProgressView *prog in cell.contentView.subviews) {
            if ([prog isKindOfClass:[UIProgressView class]]){
                if (prog.progress == 1) {
                    [prog removeFromSuperview];
                    cell.cellItemButton.hidden = NO;
                    DataBaseClass *itemObj = [appDelegate.itemArray objectAtIndex:indexPath.row];
                    NSString *imageLocalFilePath = nil;
                    if ([[tempitemStatusArray objectAtIndex:indexPath.row] isEqualToString:@"Available"]){
                        cell.cellItemButton.userInteractionEnabled = YES;
                        cell.userInteractionEnabled = YES;
                        cell.cellItemProgress.hidden = YES;
                        [cell.cellItemButton setTitle:@"" forState:UIControlStateNormal];
                        [cell.cellItemButton setBackgroundImage:[UIImage imageNamed:@"available_bttn_img_normal"] forState:UIControlStateNormal];
                        [cell.cellItemButton setBackgroundImage:[UIImage imageNamed:@"available_bttn_img_pressed"] forState:UIControlStateHighlighted];
                        [cell.cellItemButton addTarget:self action:@selector(confirmationAlert:) forControlEvents:UIControlEventTouchUpInside];
                    }else if ([[tempitemStatusArray objectAtIndex:indexPath.row] isEqualToString:@"Active"]) {
                        cell.cellItemButton.userInteractionEnabled = YES;
                        cell.userInteractionEnabled = YES;
                        cell.cellItemProgress.hidden = YES;
                        [cell.cellItemButton setTitle:@"" forState:UIControlStateNormal];
                        [cell.cellItemButton setBackgroundImage:[UIImage imageNamed:@"active_bttn_img_normal"] forState:UIControlStateNormal];
                        [cell.cellItemButton setBackgroundImage:[UIImage imageNamed:@"active_bttn_img_normal"] forState:UIControlStateHighlighted];
                        [cell.cellItemButton addTarget:self action:@selector(alert) forControlEvents:UIControlEventTouchUpInside];
                    }

                    imageLocalFilePath = [NSString stringWithFormat:@"%@",itemObj.availableLocalIconPath];
                    if ([imageLocalFilePath isEqualToString:@""]) {
                        [cell.cellitemImage setImage:[UIImage imageNamed:@"item01.png"]];
                    }else {
                        [cell.cellitemImage setImage:[UIImage imageWithContentsOfFile:imageLocalFilePath]];
                    }
                    cell.cellItemName.text = [NSString stringWithFormat:@"%@",[tempItemNameArray objectAtIndex:indexPath.row]];

                    [cell.contentView reloadInputViews];
                }
            }
        }

    }else {
        for (UIProgressView *prog in cell.contentView.subviews) {
            if ([prog isKindOfClass:[UIProgressView class]]){
                if (prog.progress == 1) {
                    [prog removeFromSuperview];
                    cell.cellItemButton.hidden = NO;
                    cell.cellItemButton.userInteractionEnabled = YES;
                    cell.userInteractionEnabled = YES;
                    [cell.cellItemButton setTitle:@"" forState:UIControlStateNormal];
                    [cell.cellItemButton setBackgroundImage:[UIImage imageNamed:@"active_bttn_img_normal"] forState:UIControlStateNormal];
                    [cell.cellItemButton setBackgroundImage:[UIImage imageNamed:@"active_bttn_img_normal"] forState:UIControlStateHighlighted];
                    [cell.cellItemButton removeTarget:nil action:NULL forControlEvents:UIControlEventAllEvents];
                    [cell.cellItemButton addTarget:self action:@selector(alert) forControlEvents:UIControlEventTouchUpInside];
                }
            }
        }        
    }

    return cell;
}

person Mithuzz    schedule 03.09.2012    source источник
comment
Вы никогда не выпускаете свою камеру, из-за которой происходит утечка. Когда вы возвращаете ячейку из своего метода getCellContentView, вызовите для нее autorelease. Я также хотел бы отметить, что вы организовали свой код таким образом, что это противоречит цели повторного использования ячеек.   -  person Jason Coco    schedule 03.09.2012
comment
что именно делает метод getCellContentView?   -  person Malloc    schedule 03.09.2012
comment
Я попробовал авторелиз, как сказал Даррен, но у меня все еще есть утечка. И как часть этого изображения и метки я также использую представление прогресса в этой ячейке. И мне нужно сохранить прогресс, даже если он перейдет к другому представлению.   -  person Mithuzz    schedule 03.09.2012
comment
@Malloc это установка объектов для пользовательской ячейки.   -  person Mithuzz    schedule 03.09.2012


Ответы (2)


В вашем методе

- (UIMenuItemCell *) getCellContentView:(NSString *)cellIdentifier

Использовать:

UIMenuItemCell *cell = [[[UIMenuItemCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];

Отредактировано, чтобы ответить на комментарии:

Правильный способ высвобождения iVars — это метод Dealloc. Если он не вызывается, это означает, что ваши UIMenuItemCells не освобождаются. Возможно, это связано с тем, как работает ваша реализация; вы создаете повторно используемую ячейку для каждой строки в представлении таблицы. Я думаю, что если вы пометите ячейку для повторного использования, она не будет выпущена до тех пор, пока не будет выпущено табличное представление.

Вы можете проверить это, увидев, освобождается ли вся память при освобождении табличного представления (если это происходит в вашем приложении). Это будет означать, что на самом деле у вас нет утечки, просто ваше приложение использует много памяти (скорее всего, без необходимости). Вы также можете проверить, увеличивается ли память, когда вы прокручиваете строки, которые вы уже создали, обратно на экран, потому что в этом случае я думаю, что вы будете повторно использовать свои ячейки, поэтому память не должна увеличиваться. Вы также можете попробовать инициализировать ячейки табличного представления с помощью nil для идентификатора ячейки, чтобы они освобождались при прокрутке экрана.

Вам, вероятно, следует попытаться переработать свой код, чтобы вы действительно повторно использовали свои ячейки. В противном случае прокрутка, скорее всего, будет довольно прерывистой.

person Darren    schedule 03.09.2012
comment
@john Если вы автоматически освобождаете ячейку, утечки больше нет. Если вы все еще видите его, это означает, что вы не опубликовали свой фактический код вырезания и вставки. Если вы не опубликуете свой фактический код, мы не сможем вам помочь. - person Jason Coco; 03.09.2012
comment
спасибо за ваш ответ, я обновил код, в дополнение к этому мне нужно сохранить прогресс-бар даже после некоторых переходов. Вот почему я боюсь выпускать всю ячейку. Я попробовал автозапуск, как вы сказали, но безрезультатно. Пожалуйста, проверьте код. - person Mithuzz; 03.09.2012
comment
@John Выпускаете ли вы свои синтезированные iVars в методе Dealloc UIMenuItemCell? - person Darren; 03.09.2012
comment
Нет, но я добавил метод -(void)dealloc в UIMenuItemCell.m и попытался освободить iVars, но этот метод не был вызван. Есть ли правильный способ освободить объекты в подклассе? - person Mithuzz; 03.09.2012

Я встречаю аналогичную проблему и, наконец, решаю ее.

потому что ваша ячейка таблицы будет повторно использоваться позже,

поэтому просто вызовите removeFromSuperview, прежде чем добавлять подвиды в ячейку.

person lbsweek    schedule 23.01.2014