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


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

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

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

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

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

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

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

Ответ 1

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

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

Что вам нужно сделать, так это создать хранилище для ваших состояний галочки - это простой массив, содержащий 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 для вашего хранилища данных;)