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


iOS TableView от Apple и повторное использование ячеек убивают меня. Я искал, искал и изучал, но не могу найти хороших документов или хороших ответов. Проблема в том, что когда TableView повторно использует ячейки, такие вещи, как галочки (принадлежность ячейки), установленные для выбранной ячейки, повторяются в ячейках ниже в представлении таблицы. Я понимаю, что повторное использование ячеек задумано из-за ограничений памяти, но если у вас есть список, скажем, из 50 элементов, и он начинает устанавливать дополнительные галочки там, где они не нужны, это делает все усилия бесполезными.

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

У Apple даже есть пример проекта под названием TouchCell, который вы можете загрузить из центра разработки, который должен показать другой способ установки галочки с использованием настраиваемой ячейки с элементом управления изображением слева. В проекте для источника данных используется объект словаря, а не массив с возможностью отключения звука, поэтому для каждого элемента существует строковое значение и проверяемое значение типа bool. Предполагается, что это значение типа bool проверено для установки флажка, чтобы можно было отслеживать выбранные элементы. Этот пример проекта также демонстрирует это дурацкое поведение, как только вы заполняете TableView более чем 15 ячейками. Повторное использование ячеек начинает ставить ненужные галочки.

Я даже пробовал поэкспериментировать с использованием действительно уникального идентификатора ячейки для каждой ячейки. Поэтому вместо того, чтобы каждая ячейка имела что-то вроде @ "Acell", я использовал статическое int, преобразованное в строку, чтобы ячейки получили @ "cell1", @ "cell2" и т. Д. Однако во время тестирования я мог видеть, что сотни новых ячеек, где генерируется при прокрутке, даже если в таблице было всего 30 элементов.

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

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

Кто-нибудь придумал элегантное решение этого раздражающего поведения?


person nick    schedule 11.06.2011    source источник


Ответы (1)


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

  • Используйте один идентификатор для одного типа ячейки. Использование нескольких идентификаторов действительно необходимо только тогда, когда вы используете разные подклассы UITableViewCell в одном табличном представлении, и вам нужно полагаться на их различное поведение. для разных ячеек
  • Ячейка, которую вы повторно используете, может находиться в любом состоянии, что означает, что вам нужно снова настроить все аспекты ячейки, особенно checkmars / images / text / accessoryViews / accessoryTypes и т. Д.

Что вам нужно сделать, так это создать хранилище для состояний ваших флажков - это должен сделать простой массив, содержащий bools (или NSArray, содержащий логические объекты NSNumber соответственно). Затем, когда вам нужно создать / повторно использовать ячейку, используйте следующую логику:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *reuseIdentifier = @"MyCellType";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
    if(cell == nil) {
        /* create cell here */
    }
    // Configure cell now
    cell.textLabel.text = @"Cell text"; // load from datasource
    if([[stateArray objectAtIndex:indexPath.row] boolValue]) {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
    } else {
        cell.accessoryType = UITableViewCellAccessoryNone;
    }
    return cell;
}

тогда вам придется реагировать на нажатия:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [stateArray replaceObjectAtIndex:indexPath.row withObject:[NSNumber numberWithBool:![[stateArray objectAtIndex:indexPath.row] boolValue]]];
    [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}

Просто не забудьте использовать NSMutableArray для своего хранилища данных;)

person Martin Ullrich    schedule 11.06.2011
comment
Спасибо за предложение, Мартин. Я попробую, хотя он действительно выглядит как вариант кода в проекте TouchCell из DevCenter (код Apple). Они используют класс Dictionary для хранения значения BOOL и текста ячейки. Он отлично работает всего с несколькими ячейками (9 или 10), но срабатывает точно так же, когда ячейки повторно используются от 20 до 30 или более ... Кстати, сегодня я пробовал запустить тестовое приложение через инструменты, то, которое Я вообще не использую повторно ячейки, и на самом деле он использовал меньше памяти, чем предпочтительный метод. (Если я правильно понимаю инструменты!). - person nick; 11.06.2011
comment
Я не внимательно изучал их код, но вполне вероятно, что они похожи, потому что это тот путь, которым вы хотите идти. возможно, вам стоит загрузить где-нибудь свой код и опубликовать ссылку в качестве комментария здесь - person Martin Ullrich; 11.06.2011
comment
Я просто делаю приложение с одним представлением, чтобы опробовать ваше предложение. Я создам два отключаемых массива: один для отображаемых данных (значения NSString) и второй массив для состояний BOOL, как вы предложили. - person nick; 11.06.2011
comment
вы используете несколько разделов? .. я не думаю, что мы можем сделать для вас больше без кода :( - person Martin Ullrich; 11.06.2011
comment
Я опубликую некоторые результаты, Мартин. Я просто пытаюсь написать код, одновременно готовя еду. Ты не в Дании? - person nick; 11.06.2011
comment
Мартин, я думаю, что ваше предложение работает, и даже лучше, я думаю, что понимаю, почему оно работает! Правильно ли я полагаю, что когда ячейка или группа ячеек исчезают из поля зрения, они уничтожаются или освобождаются? И они никогда не вспомнят такие вещи, как аксессуары? - person nick; 11.06.2011
comment
Кстати, это проект, над которым я работаю (в качестве учебного опыта будет использоваться группировка и потребуется массив массивов. Это будет беспорядочно, если мне придется создавать массив состояний ячеек для каждого массива в группах. Как вы думаете, словарь объект был бы лучше для этого? - person nick; 11.06.2011
comment
ячейки не разрушаются, используются повторно. поэтому, когда он уходит с экрана, он помещается в пул. когда вам нужно вернуть ячейку для следующей строки, которая появляется на экране, вы берете любую ячейку из пула и настраиваете ее так, как вам нужно. когда вы получите ячейку (dequeReusable ..), она будет в том же состоянии, в котором она покинула экран (= то же состояние, в котором вы настроили ее в последней ячейкеForRowAtIndexPath). на самом деле не имеет значения, что вы используете в качестве источника данных. NSIndexPath очень удобен для навигации по массивам массивов, но вы также можете использовать словари. - person Martin Ullrich; 12.06.2011
comment
Мартин, спасибо за вашу помощь и код. Он отлично работает, но для сгруппированных таблиц с множеством разделов массив состояний для каждого источника данных может плохо масштабироваться. Я попытаюсь погрузиться в Core Data. В любом случае, я сохранил ваши примеры, потому что они отлично решают проблему! Привет, Ник - person nick; 13.06.2011
comment
Привет, Мартин, не могли бы вы, взгляните на эту проблему, которая у меня сейчас возникла. Это очень похоже на эту проблему, и я не смог ее решить, как и никто другой stackoverflow.com/questions/21126654/ - person Chisx; 19.01.2014
comment
@Martin, спасибо вам огромное! ... вы также очень помогли мне с повторным использованием сотовых! - person Pangu; 09.11.2014