Как избежать повторяющихся строк при создании UITableViewCell из подпредставлений UILabel

Я загружаю массив элементов словаря, содержащих данные о состоянии США, в UITableView, и у меня возникают повторяющиеся строки, когда пользователь прокручивает вниз до закадровых элементов - строка 1 дублируется в строке 8, строка 2 дублируется в строке 9 и т. д.

Я рассмотрел следующие вопросы SO и реализовал некоторые из их предложений (без успеха):

2994472 — в моем UITableView есть повторяющиеся строки

7056578 - повторяющиеся ячейки UITableView при прокрутке

UITableViewCell — это пользовательская конструкция, созданная из UILabels. Вот код в cellForRowAtIndexPath.

00    const int ABBREVIATION = 1, STATE = 2 // Declared outside cellForRowAtIndexPath


01    static NSString *CellIdentifier = @"Cell";
02    
03    UILabel *abbreviation, *state;
04    
05    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
06    if (cell == nil) {
07        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault         
08              reuseIdentifier:CellIdentifier];
09        
10        abbreviation = [[UILabel alloc] initWithFrame:CGRectMake(7.0, 1.0, 34.0, 30.0 )];
11        abbreviation.tag = ABBREVIATION; 
12        abbreviation.font = [UIFont fontWithName:@"Helvetica-Bold" size:20.0];
13        abbreviation.textAlignment = UITextAlignmentLeft;
14        abbreviation.textColor = [UIColor blackColor];
15
16        state = [[UILabel alloc] initWithFrame:CGRectMake(42.0, 1.0, 158.0, 30.0)];
17        state.tag = STATE;
18        state.font = [UIFont fontWithName:@"Helvetica-Bold" size:20.0];
19        state.textAlignment = UITextAlignmentLeft;
20        state.textColor = [UIColor blackColor];
21
22        [cell.contentView addSubview:abbreviation];
23        [cell.contentView addSubview:state];
24    
25        [cell setAccessoryType:UITableViewCellAccessoryDetailDisclosureButton];
26        [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
27    }
28    
29    abbreviation.text = [[self.primaries objectAtIndex:indexPath.row] objectForKey:@"abbreviation"];
30    state.text = [[self.stateInfo objectAtIndex:indexPath.row] objectForKey:@"name"];
31    
32    return cell;

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

29   abbreviation.text = [[self.primaries objectAtIndex:indexPath.row] objectForKey:@"abbreviation"] ?
                         [[self.primaries objectAtIndex:indexPath.row] objectForKey:@"abbreviation"] :
                         @"";

30   state.text = [[self.stateInfo objectAtIndex:indexPath.row] objectForKey:@"name"] ?
                  [[self.stateInfo objectAtIndex:indexPath.row] objectForKey:@"name"] : 
                  @"";

Это не сработало, дублирование все еще происходит, начиная с строки 8.

Что, по-видимому, решает проблему, так это ссылка на тег UILabel при настройке текста метки для детализации до фактического подпредставления.

29  ((UILabel *)[cell viewWithTag:ABBREVIATION]).text = [[self.primaries objectAtIndex:indexPath.row] objectForKey:@"abbreviation"];
30  ((UILabel *)[cell viewWithTag:STATE]).text = [[self.primaries objectAtIndex:indexPath.row] objectForKey:@"name"];

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


person billmaya    schedule 04.12.2011    source источник
comment
В вашей первой версии ошибка возникает из-за того, что вы сохраняете последнюю выделенную версию аббревиатуры и состояния ваших переменных, ваша последняя версия верна, потому что она связывает переменные с ячейкой. Но у вас есть ответ, был ли вопрос?   -  person gregory    schedule 04.12.2011
comment
Как бы вы предложили выпустить последние выделенные версии аббревиатуры и состояния (я использую iOS 5 с включенным ARC для этого файла)? Кроме того, я разместил это на случай, если кто-то еще столкнется с подобной ситуацией.   -  person billmaya    schedule 05.12.2011
comment
Вы должны просто отпустить его после добавления с помощью addSubView, addSubView сохранит его, и, отпустив, вы передадите управление памятью коду uitbaleview. С вашим опубликованным кодом использование памяти, скорее всего, будет продолжать расти.   -  person gregory    schedule 05.12.2011
comment
релиз недоступен в режиме автоматического подсчета ссылок iOS. Вы предлагаете отключить ARC для этого файла или всего проекта?   -  person billmaya    schedule 07.12.2011
comment
Нет, я сделал этот комментарий, игнорируя то, что вы включили ARC, и я сам не использовал его. Но, как я понимаю, аббревиатура вашего кода и состояние должны быть объявлены как ivars, поэтому в рамках времени жизни экземпляра я бы предложил объявить их локально, тогда ARC должен избавиться от них в конце метода.   -  person gregory    schedule 07.12.2011


Ответы (2)


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

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

(A) NSLog(@"%@", state.text);
(B) NSLog(@"%@", ((UILabel *)[cell viewWithTag:STATE]).text);

Представленные результаты интересны и проливают некоторый свет на ситуацию.

 (A)               (B)
 Iowa              Iowa
 New Hampshire     New Hampshire
 South Carolina    South Carolina
 Florida           Florida
 Nevada            Nevada
 Colorado          Colorado
 Minnesota         Minnesota
 (null)            Iowa
 (null)            New Hampshire
 (null)            SouthCarolina
 (null)            Florida

(Нулевые) значения появляются при прокрутке вверх для отображения дополнительных состояний.

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

29    abbreviation.text = [[self.primaries objectAtIndex:indexPath.row] objectForKey:@"abbreviation"];
30    state.text = [[self.stateInfo objectAtIndex:indexPath.row] objectForKey:@"name"];

Но поскольку они были автоматически разыменованы ARC, они больше не существуют, не могут быть установлены и возвращают значение null. Однако ячейки, содержащие исходные значения, «извлекаются из очереди» и повторно используются со старыми данными, что приводит к появлению дубликатов.

Дайте мне знать, если я полностью ошибаюсь с этой гипотезой.

person billmaya    schedule 13.12.2011
comment
Вы правы на 100%. Он повторно использует старые ячейки с их старыми данными. Вам нужно заново инициализировать все в ячейке. Спасибо! - person Nico Huysamen; 14.02.2012

Похоже, что в случае, когда dequeueReusableCellWithIdentifier: возвращает существующую ячейку представления таблицы, так что ваш блок if пропускается, ваши переменные abbreviation и state не установлены. Таким образом, в этом случае (что произойдет, когда вы начнете прокручивать и, таким образом, отображать повторно используемые ячейки), abbreviation и state равны нулю в конце вашей функции, поэтому метки повторно используемых ячеек не обновляются, как вы ожидаете. Вероятно, вам нужен блок else, в котором вы устанавливаете аббревиатуру и переменные состояния, чтобы они указывали на правильные подпредставления cell.

person Mike Mertsock    schedule 04.12.2011
comment
Но строки кода, которые задают текстовые значения для аббревиатуры и состояния, находятся за пределами блока if (cell == nil). То, что вы говорите, верно: когда существующая ячейка используется повторно, код создания пропускается, но всегда будет выполняться код установки значения. Вы говорите, что, поскольку мы повторно используем ячейку, ссылки на подпредставления UILabel в повторно используемой ячейке равны нулю и недоступны? - person billmaya; 04.12.2011
comment
Возможно, когда я читал ваш вопрос, я пропустил viewWithTag строки кода внизу вашего вопроса. Эти два оператора viewWithTag — это то, что я предлагал вам поместить в блок else. Возможно, вызовы viewWithTag возвращают ноль, здесь я ухожу из памяти, но вам может понадобиться использовать [cell.contentView viewWithTag:ABBREVIATION] и т. д. вместо [cell viewWithTag:ABBREVIATION]. - person Mike Mertsock; 04.12.2011
comment
Работают как [cell viewWithTag:ABBREVIATION], так и [cell.contentView viewWithTag:ABBREVIATION]. - person billmaya; 05.12.2011