Изменение объекта в UITableViewCell также изменяет объект повторно используемого UITableViewCell - PullRequest
0 голосов
/ 08 февраля 2011

Код обновлен до рабочей версии. Еще раз спасибо за помощь:)

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

    // Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *cellIdentifier = @"PeopleFilterTableViewCell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

    if (cell == nil) {
        [[NSBundle mainBundle] loadNibNamed:@"PeopleFilterTableViewCell" owner:self options:nil];
        cell = peopleFilterTableViewCell;
        self.peopleFilterTableViewCell = nil;
    }

    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    PeopleFilterTableViewCell* tableViewCell = (PeopleFilterTableViewCell *) cell;

    /* Set direct button name */
    Person* personAtRow = [directsToShow objectAtIndex:indexPath.row];
    [tableViewCell.directButton setTitle:personAtRow.name forState:UIControlStateNormal];

    /* Set direct head count */
    tableViewCell.headcountLabel.text = [NSString stringWithFormat:@"%d", personAtRow.totalHeadCount];

    UIImage* unselectedImage = [UIImage imageNamed:@"filterButton.png"];
    UIImage* selectedImage = [UIImage imageNamed:@"filterButtonClosed.png"];

    UIButton* newFilterButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    /* Set filter button image */
    if(personAtRow.filtered){
        [newFilterButton setSelected:YES];
    } else {
        [newFilterButton setSelected:NO];
    }
    tableViewCell.filterButton = newFilterButton;

    return cell;
}

Мне кажется, что это нормально работает, но одна проблема возникла с кодом после / * установить изображение кнопки фильтра * / comment.

Кнопка фильтра - это UIB-кнопка в моем настраиваемом кончике ячейки, которая должна отражать состояние массива модели, содержащего объекты «Персона», у которых есть поле, которое можно переключать для представления того, фильтруются они или нет.

Я разрешаю пользователю обновлять этот объект модели с помощью специального метода делегата на моем контроллере верхнего уровня, который всякий раз, когда пользователь нажимает кнопку фильтра, обновляет модель и состояние кнопки, а также обновляет дополнительно. mapViewController с некоторыми данными для отображения в зависимости от состояния модели:

- (void)updateViews:(id)sender {
    UIImage* unselectedImage = [UIImage imageNamed:@"filterButton.png"];
    UIImage* selectedImage = [UIImage imageNamed:@"filterButtonClosed.png"];

    int row = [self rowOfCellSubView:sender];

    Person* personToFilter = [self.directsToBeShown objectAtIndex:row];
    NSLog(@"Filtering person with corpId: %@, name: %@", personToFilter.corpId, personToFilter.name);
    if (personToFilter.filtered){
        //update button image
        [sender setImage:unselectedImage forState:UIControlStateNormal];
        [sender setSelected:NO];
        //add person back.
        Person* directFiltered = [self.directsToBeShown objectAtIndex:row];
        directFiltered.filtered = NO;
        NSLog(@"Filtering person with corpId: %@, name: %@, filtered: %d", directFiltered.corpId, directFiltered.name, directFiltered.filtered);

    } else {
        //update button image
        [sender setImage:selectedImage forState:UIControlStateSelected];
        [sender setSelected:YES];
        //remove person.
        personToFilter.filtered = YES;

        NSLog(@"Filtering person with corpId: %@, name: %@, filtered: %d", personToFilter.corpId, personToFilter.name, personToFilter.filtered);
    }

    [self updateSitesToShow];
    [self.mapViewController performSelectorOnMainThread:@selector(updateDisplay) withObject:nil waitUntilDone:NO];

}

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

Однако проблема в том, что когда я нажимаю кнопку filterButton в одной строке ячейки, а затем прокручиваю несколько строк вниз, я замечаю, что другая кнопка фильтра в другой ячейке теперь имеет то же состояние, что и кнопка, которую я щелкнула несколькими строками выше , Если я снова прокручиваю вверх, исходная кнопка, которую я нажал «вкл», теперь кажется «выключенной», но строка под ней теперь отображается «вкл. Конечно, все это влияет на фактическое отображение кнопок. Фактическое состояние кнопок соответствует и работает правильно.

Я знаю, что эта проблема должна быть связана с тем фактом, что мои ячейки используются повторно, и я предполагаю, что как-то одинаковые кнопки используются для разных строк ячеек. Я в растерянности относительно того, как это происходит, так как я создаю новую кнопку фильтра для каждой ячейки, независимо от того, используется ли ячейка повторно или нет, и сбрасываю свойство filterButton ячейки, чтобы оно было вновь созданным объектом. Например, обратите внимание, что текст свойства headCount, который является UILabel, также определенным в кончике ячейки, также переназначается новому объекту String для каждой ячейки и отображается правильно для каждой строки.

Я боролся с этой проблемой уже несколько дней. Буду очень признателен за любую помощь или предложения.

Ответы [ 2 ]

0 голосов
/ 08 февраля 2011

Это типичная проблема, которая возникает, когда вы изменяете структуру представления ячейки после того, как она была снята с очереди, в то время как вы можете изменять структуру ячейки только на этапе alloc / init. После удаления или alloc / init вам разрешено настраивать только содержимое, а не структуру.

В вашем случае, когда ячейка (скажем, это строка 0) загружается из пера, создается внутренняя структура подпредставлений (как определено в пике), и экземпляр filterButton назначается одному из этих подпредставлений. Но несколькими строками ниже вы создаете новый UIButton и заменяете экземпляр filterButton этим новым, но реальное подпредставление кнопки останется прежним! Теперь, когда вы нажимаете кнопку, конечно, «настоящая» кнопка (то есть кнопка в иерархии представлений ячеек, которая была изначально создана пером) будет вызвана, обратный вызов вызван, и состояние будет изменено.

Позже, когда вы прокрутите эту ячейку строки-0, она будет удалена с экрана и заполнена, а затем снова использована для другой ячейки, скажем, строки-9. На этом этапе бывшая ячейка row-0 будет повторно использоваться для ряда row-9, но настройка filterButton по-прежнему не действует, поскольку вы продолжаете использовать исходную кнопку, изначально загруженную Nib для ячейки row-0. Конечно, вы увидите, что эти состояния кнопок будут прокручиваться во время прокрутки, так как они каждый раз по-разному используются механизмом очереди (поэтому row-0 -> row-9, позже row-0 -> row-8 и т. Д.) .

Решение состоит в том, чтобы просто изменить статус кнопки: [self.filterButton setSelected: NO | YES] и не изменять содержимое представления ячейки.

Итак, золотое правило: НИКОГДА не меняйте структуру клетки после того, как вы ее бросили. Если вам нужно изменить структуру, тогда используйте РАЗЛИЧНЫЕ идентификаторы ячеек. Конечно, чем больше настраиваемая ячейка, тем легче ее использовать.

0 голосов
/ 08 февраля 2011

Табличные представления кэшируют их ячейки, чтобы вы могли использовать их повторно, что вы делаете при каждом вызове dequeueReusableCellWithIdentifier:. Вы должны вызвать setSelected: до конца вашего tableView:cellForRowAtIndexPath: метода, чтобы синхронизировать состояние кнопки с состоянием экземпляра Person, который соответствует текущей строке.

Еще одна вещь, которую следует учитывать, это то, что создание новых экземпляров кнопок каждый раз, когда вы возвращаете ячейку, довольно расточительно. Рассмотрите возможность создания и настройки кнопок (настройки заголовков, изображений и т. Д.) Один раз для экземпляра ячейки внутри блока if, в который вы загружаете ячейку из файла nib.

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