UITableViewCell селектор setSelected: анимированный: вызывается много раз?

Я обнаружил странное поведение с setSelected: анимированным: в моем пользовательском классе UITableViewCell. Я обнаружил, что эта функция вызывается несколько раз, если я нажимаю на ячейку в своей таблице. Мне интересно, если это нормальное поведение или ошибка в моем коде.

Чтобы помочь в отладке, я изменил функцию setSelected: анимированный: в моей собственной реализации класса UITableViewCell как таковой:

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {

[super setSelected:selected animated:animated];

// Configure the view for the selected state.
if (selected)
    NSLog(@"Yes %X", &self);
else
    NSLog(@"No %X", &self);

}

Если я нажимаю на ячейку в симуляторе, вот что я получаю в консоли:

2011-03-22 22:05:26.963 marketPulse[3294:207] Yes BFFFDDD0
2011-03-22 22:05:26.964 marketPulse[3294:207] Yes BFFFDE30

Вы бы подумали, что я получу только 1 запись, так как я только нажал на 1 ячейку.

И если после этого я нажимаю на другую ячейку:

2011-03-22 22:07:11.014 marketPulse[3294:207] No BFFFD890
2011-03-22 22:07:11.016 marketPulse[3294:207] No BFFFDD00
2011-03-22 22:07:11.017 marketPulse[3294:207] Yes BFFFDDD0
2011-03-22 22:07:11.017 marketPulse[3294:207] Yes BFFFDE30

Если я нажимаю одну и ту же ячейку 2 раза подряд, я получаю больше 2 Да:

2011-03-22 22:08:41.067 marketPulse[3294:207] Yes BFFFDDD0
2011-03-22 22:08:41.068 marketPulse[3294:207] Yes BFFFDE30
2011-03-22 22:08:41.069 marketPulse[3294:207] Yes BFFFDE30

Чем больше раз я нажимаю одну и ту же ячейку, тем больше Да я получу, и если после этого я нажму на другую ячейку, я получу много Нет

Я поставил точку останова перед NSLog и, глядя на отладчик, кажется, что все повторяющиеся вызовы происходят от одного и того же объекта.

Вот часть моей функции tableView: cellForRowAtIndexPath:, чтобы вы могли видеть, как обрабатываются мои ячейки:

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


static NSString *ContentCellIdentifier = @"newsTableCellContent";

UITableViewCell *cell;


//index of cell data in tableData
NSUInteger index = indexPath.row / 2;

...

//content of story
else if( [indexPath row] % 2 == 1 ) {

    cell = [tableView dequeueReusableCellWithIdentifier:ContentCellIdentifier];

    if (cell == nil) {
        NSArray *topLevelObjects = [[NSBundle mainBundle]
                                    loadNibNamed:@"newsTableCells"
                                    owner:nil options:nil];

        for (id currentObject in topLevelObjects) {
            if ( [currentObject isKindOfClass:[newsTableCellContent class]] ) {
                cell = currentObject;
                break;
            }
        }
    }

    ((newsTableCellContent *)cell).content.text = [[tableData objectAtIndex:index] description];

}   

return cell;
}

Все работает отлично, поэтому трудно определить, намерены ли повторные вызовы setSelected: анимированные:. Если это нормальная работа, я могу обойтись другим методом, но я просто хотел бы знать, произойдет ли это или нет.

Спасибо

Ответы

Ответ 1

Что происходит, просто, что UITableView отслеживает, какие ячейки выбраны в таблице.

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

Когда вы нажимаете на ячейку, происходит несколько вещей: ранее выбранная ячейка отменяется (используя setSelected:). Новая ячейка подсвечивается. Он не подсвечивается (по крайней мере, если вы нажимаете вместо того, чтобы удерживать палец вниз), и вызывается метод setSelected:, потому что была выбрана новая ячейка. Этот.

Второй вызов - это вызов с задержкой выполнения, возможно, из точки, где представление таблицы еще не знает, каково конечное состояние таблицы. Этот вызов переходит к _selectAllSelectedRows, который, как следует из названия, вызывает "setSelected: animated:" для всех выбранных строк. Это второй звонок. Причина этого, скорее всего, будет связана с потенциальными проблемами из-за того, что табличное представление находится в "переходе", но кто знает.

Является ли это ошибкой или нет для интерпретации. Исправление дублированных вызовов состоит в следующем:

if (self.selected == selected) return;

перед вызовом super (вам не нужно называть super, если self.selected == selected).

Ответ 2

Это нормальное поведение, если вы используете iPad. (он вызывается только один раз на iPhone).

Чтобы перестать получать несколько "setSelected: YES" или несколько "setSelected: NO", все, что вам нужно сделать, это следующее:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

Теперь, 1 щелчок по любой ячейке дает вам:

  • 1 запись setSelected: YES animated: NO
  • 1 запись таблицыView: didSelectRowAtIndexPath:
  • 1 запись setSelected: NO анимированная: YES

Таким образом, звонки теперь стабильны независимо от того, что вы делаете.

Ответ 3

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

Если вы действительно хотите увидеть, что происходит, добавьте NSLog в tableView: cellForRowAtIndexPath: который будет записывать indexPath и возвращенную ячейку.

Весь журнал должен дать вам хорошее представление о том, что происходит внутри и почему. Я полагаю, что это будет что-то вроде этого (Clicked on IndexPath 1:1)

Дайте мне ячейку по 1: 0 (ранее выбранная ячейка).
Снять выделение 1: 0
Дайте мне ячейку 1: 0 снова (обновляется после отмены)
Снять выделение 1: 0 (обновить выбранный флаг в этой ячейке и вызвать анимацию)
Дайте мне ячейку 1:1
Выберите 1:1
Дайте мне ячейку 1:1 снова (обновляется после выбора)
Выберите 1:1 (обновите выбранный флаг в этой ячейке и запустите анимацию)

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

Ответ 4

В идеале вы не должны вызывать setSelected из любого места вашего кода. UIKit позаботится о его вызове.

Если вы хотите показать ячейку/строку, выбранную в cellForRowAtIndexPath, просто вызовите

tableView.selectRowAtIndexPath(indexPath, animated: true, scrollPosition: .None)

для этого конкретного indexPath.

Снова никогда не вызывайте setSelected явно, если вы действительно не хотите.