Утечка памяти в ячейке UITableView - PullRequest
2 голосов
/ 30 января 2012

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

Вот что происходит:

У меня есть NSMutableArray, заполненный NSDictionaries (контактная информация), который я загружаю из базы данных sql каждый раз, когда пользователь выбирает новую индексную букву, массив заполняется информацией для этих контактов.

Поскольку я использую массив переменных экземпляра для хранения данных, я рисую что-то вроде этого перед каждым новым обменом новыми данными:

if (currentConnections != nil) {
    [currentConnections release];
    currentConnections = nil;
}

Эффективно избавился бы от моих старых данных, прежде чем я их сбросил.
Однако здесь начинается странность. В моем tableView:cellForRowAtIndexPath: я звоню вот так:

NSString *firstname = [[currentConnections objectAtIndex:indexPath.row]
                       objectForKey:@"firstname"];
UILabel *name = [[UILabel alloc]
                 initWithFrame:CGRectMake(75, 12, 190, 15)];
name.font = [UIFont fontWithName:@"Gotham-Medium.ttf" 
                            size:12];
name.textColor = [UIColor whiteColor];
name.backgroundColor = [UIColor clearColor];
name.text = firstname;

Где текущие соединения - это массив словарей. Затем я добавляю UILabel как подпредставление ячейки:

[cell addSubview:name];
[name release];

Поведение из этого таково:

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

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

Есть идеи, что может быть причиной этой утечки?

редактирование:

Это текущий табличный вид: cellForRowAtIndexPath:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 {

static NSString *MyIdentifier = @"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];

cell.accessoryType = UITableViewCellAccessoryNone;

if (cell == nil) {
    NSLog(@"within");
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier] autorelease];
}

if (!ALOCATED) {


cellName = [[ UILabel alloc ]
                 initWithFrame:CGRectMake(75, 12, 190, 15)
                 ];
cellName.font = [ UIFont 
             fontWithName:@"Gotham-Medium.ttf" 
             size:12 
             ];
cellName.textColor = [ UIColor whiteColor ];
cellName.backgroundColor = [ UIColor clearColor ];

NSString *firstname = [[ currentConnections 
                        objectAtIndex:indexPath.row 
                        ] objectForKey:@"firstname" 
                       ];

firstname = [ firstname stringByAppendingString:@" " ];

NSString *lastname = [[ currentConnections 
                       objectAtIndex:indexPath.row 
                       ] objectForKey:@"lastname" 
                      ];

UIImage *profPic = [[ currentConnections 
                     objectAtIndex:indexPath.row 
                     ] objectForKey:@"profilepicture" 
                    ];
connectionPhoto = [[ UIImageView alloc ] initWithFrame:CGRectMake(10, 8, 56, 56) ];
connectionPhoto.image = profPic;




NSString *fullname = [ firstname stringByAppendingString:lastname ];

cellName.text = fullname;


[ cell addSubview:cellName ];



cellTitle = [[ UILabel alloc ]
                 initWithFrame:CGRectMake(75, 31, 260, 13)
                 ];
cellTitle.font = [ UIFont 
             fontWithName:@"ArialMT" 
             size:10 
             ];
cellTitle.textColor = [ UIColor whiteColor ];
cellTitle.backgroundColor = [ UIColor clearColor ];
cellTitle.text = [[ currentConnections 
                  objectAtIndex:indexPath.row 
                  ] objectForKey:@"title" 
                 ];


[ cell addSubview:cellTitle ];
[ cell addSubview:connectionPhoto ];
[ profPic release ];

    ALOCATED = YES;

} else {



    cellTitle.text = [[ currentConnections 
                       objectAtIndex:indexPath.row 
                       ] objectForKey:@"title" 
                      ];

    connectionPhoto.image = [[ currentConnections 
                                                             objectAtIndex:indexPath.row 
                                                             ] objectForKey:@"profilepicture" 
                             ];


    NSString *firstname = [[ currentConnections 
                            objectAtIndex:indexPath.row 
                            ] objectForKey:@"firstname" 
                           ];

    firstname = [ firstname stringByAppendingString:@" " ];

    NSString *lastname = [[ currentConnections 
                           objectAtIndex:indexPath.row 
                           ] objectForKey:@"lastname" 
                          ];
    NSString *fullname = [ firstname stringByAppendingString:lastname ];

    cellName.text = fullname;

}

return cell;

}

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

EDIT

То, что происходило, было то, что я добавлял подпредставления к самому объекту ячейки, что вызывало утечку, поскольку они не были освобождены. Как только я начал добавлять представления в представления членов UITableViewCell, такие как cell.contentView, cell.accessoryView и т. Д., Память была освобождена. Поэтому, как упоминалось ниже, Даниель создаст пользовательскую ячейку таблицы и добавит ваши представления в свойства вашей ячейки, или добавит ваши представления в uitablecellviews участника, а не в саму ячейку. У меня сработало следующее:

   - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

static NSString *MyIdentifier = @"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];

cell.accessoryType = UITableViewCellAccessoryNone;

if (cell == nil) {

    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier] autorelease];
}




UILabel *cName = [[ UILabel alloc ]
                 initWithFrame:CGRectMake(105, 10, 190, 15)
                 ];
cName.font = [ UIFont 
             fontWithName:@"Gotham-Medium.ttf" 
             size:12 
             ];
cName.textColor = [ UIColor whiteColor ];
cName.backgroundColor = [ UIColor clearColor ];

NSString *firstname = [[ currentConnections 
                        objectAtIndex:indexPath.row 
                        ] objectForKey:@"firstname" 
                       ];

firstname = [ firstname stringByAppendingString:@" " ];

NSString *lastname = [[ currentConnections 
                       objectAtIndex:indexPath.row 
                       ] objectForKey:@"lastname" 
                      ];

NSString *fullname = [ firstname stringByAppendingString:lastname ];

cName.text = fullname;

[ cell.contentView addSubview:cName ];
[ cName release ];



cell.imageView.image = [[ currentConnections 
                     objectAtIndex:indexPath.row 
                     ] objectForKey:@"profilepicture" 
                    ];



UILabel *cTitle = [[ UILabel alloc ]
                 initWithFrame:CGRectMake(105, 25, 190, 13)
                 ];
cTitle.font = [ UIFont 
             fontWithName:@"ArialMT" 
             size:10 
             ];
cTitle.textColor = [ UIColor whiteColor ];
cTitle.backgroundColor = [ UIColor clearColor ];
cTitle.text = [[ currentConnections 
                  objectAtIndex:indexPath.row 
                  ] objectForKey:@"title" 
                 ];


[ cell.contentView addSubview:cTitle ];
[ cTitle release ];

return cell;

}

Ответы [ 2 ]

5 голосов
/ 30 января 2012

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

Проблема очевидна из кода, который вы опубликовали, вы пропускаете переменную экземпляра ячейки, также имейте в виду, что cellForRowAtIndexPath вызывается для каждой строки в таблице, поэтому сохраняя одну переменную экземпляра, чтобы отслеживать что-то добавленное к ячейка не будет работать, переменная будет продолжать перезаписываться, но в вашем случае вы пропускаете ячейки. Вы добавляете ячейки в UITableViewCell, никогда не освобождая их, а затем при следующем вызове cellForRowAtIndexPath ячейки var перезаписываются, а предыдущая утечка, потому что у вас больше нет возможности освободить ее ... Это можно исправить, выпустив ячейки ...

Теперь у вас также есть проблема использования одной переменной для отслеживания меток в ячейках, имейте в виду, что для повторного использования выделяется не одна ячейка, а действительно столько ячеек, сколько может отображаться на экране, поэтому следите одна переменная не сработает, это ваша проблема ... Чтобы решить эту проблему, я бы подкласс UITableViewCell со свойством метки и иметь метод для сброса текста метки ..

Надеюсь, это поможет

1 голос
/ 30 января 2012
  • есть так много контактов, что вы не можете загрузить все в одном массиве?
  • Вы можете использовать NSMutableArray и метод removeAllObjects.
  • в вашем коде:

    [ячейка addSubview: имя]; firstname - это строка ... вы не можете добавить NSString в качестве подпредставления ... и я рекомендую создать пользовательскую UITableviewcell, потому что ячейка перерабатывается, и когда вы используете переработанную ячейку, внутри все подпредставления добавляются во время его создания.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...