Установка стиля UITableViewCell при использовании iOS 6 UITableView dequeueReusableCellWithIdentifier: forIndexPath:

82

Я пытаюсь понять, как установить UITableViewCellStyleпри использовании новых методов в iOS 6 для UITableView.

Раньше при создании UITableViewCellя менял UITableViewCellStyleперечисление для создания различных типов ячеек по умолчанию при вызове, initWithStyle:но из того, что я могу собрать, это уже не так.

В документации Apple UITableViewуказано:

Возвращаемое значение : объект UITableViewCell со связанным идентификатором повторного использования. Этот метод всегда возвращает действительную ячейку.

Обсуждение : По соображениям производительности источник данных табличного представления обычно должен повторно использовать объекты UITableViewCell, когда он назначает ячейки строкам в своем методе tableView: cellForRowAtIndexPath:. Табличное представление поддерживает очередь или список объектов UITableViewCell, которые источник данных пометил для повторного использования. Вызовите этот метод из объекта источника данных, когда вас попросят предоставить новую ячейку для представления таблицы. Этот метод удаляет существующую ячейку из очереди, если она доступна, или создает новую на основе ранее зарегистрированного вами класса или файла пера.

Важно : вы должны зарегистрировать класс или файл пера с помощью метода registerNib: forCellReuseIdentifier: или registerClass: forCellReuseIdentifier: перед вызовом этого метода.

Если вы зарегистрировали класс для указанного идентификатора и должна быть создана новая ячейка, этот метод инициализирует ячейку, вызывая ее метод initWithStyle: reuseIdentifier:. Для ячеек на основе пера этот метод загружает объект ячейки из предоставленного файла пера. Если существующая ячейка была доступна для повторного использования, этот метод вместо этого вызывает метод prepareForReuse ячейки.

Вот как cellForRowAtIndexPathвыглядит мой новый вид после внедрения новых методов:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellIdentifier = @"cell_identifier";

    [tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:cellIdentifier];

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];

    return cell;
}

Код, который у меня есть, работает нормально, но всегда возвращает стиль по умолчанию. Как я могу изменить это , так что я могу создать ячейки с другими стилями , такими как UITableViewCellStyleDefault, UITableViewCellStyleValue1, UITableViewCellStyleValue2и UITableViewCellStyleSubtitle?

Я не хочу создавать подклассы UITableViewCell, я просто хочу изменить тип по умолчанию, как я мог это сделать до iOS 6. Кажется странным, что Apple предоставила расширенные методы, но с минимальной документацией для поддержки их реализации.

Кто-нибудь осилил такое, или столкнулся с подобной проблемой? Я изо всех сил пытаюсь найти хоть какую-то разумную информацию.

Капитан
источник

Ответы:

106

Я знаю, что вы сказали, что не хотите создавать подкласс, но это выглядит неизбежным. На основе кода сборки при тестировании в симуляторе iOS 6.0 UITableViewсоздает новые экземпляры UITableViewCell(или его подклассы), выполняя

[[<RegisteredClass> alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:<ReuseIdentifier>]

Другими словами, стиль sent ( UITableViewCellStyleDefault) кажется жестко запрограммированным. Чтобы обойти это, вам нужно будет создать подкласс, который переопределяет инициализатор по умолчанию initWithStyle:reuseIdentifier:и передает стиль, который вы хотите использовать:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    // ignore the style argument, use our own to override
    self = [super initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:reuseIdentifier];
    if (self) {
        // If you need any further customization
    }
    return self;
}

Кроме того , было бы лучше , чтобы отправить registerClass:forCellReuseIdentifier:в viewDidLoad, вместо того , чтобы делать это каждый раз , когда запрашивается клетка:

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.tableView registerClass:<RegisteredClass> forCellReuseIdentifier:<ReuseIdentifier>];
}
болот
источник
4
Я начал предполагать, что это действительно так. Это не серьезная проблема, но создание подкласса UITableViewCellдля получения других стилей по умолчанию является проблемой, поскольку это просто создает ненужные файлы. Спасибо за комментарий и подтверждение моих подозрений.
CaptainRedmuff
11
Не забывайте, что вместо создания подклассов вы можете использовать старый метод iOS5, который все еще действителен. Таким образом, вы можете инициализировать любой стиль ячейки, какой захотите. Смотрите другой ответ.
SpacyRicochet
60

dequeueReusableCellWithIdentifierне устарела, поэтому вам не нужно использовать новую dequeueReusableCellWithIdentifier:forIndexPath:.

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

Мюррей Сагал
источник
1
Проголосовали за указание на то, что вам не нужно использовать новые причудливые методы. Только если они подходят для ваших целей или альтернативы устарели.
SpacyRicochet
Если вы особенно заинтересованы, можно переопределить, dequeueReusableCellWithIdentifier:forIndexPath:чтобы некоторые идентификаторы строили ячейки старым способом (и возвращали их). Другие идентификаторы вызовут super и вернут это. Возможно, имеет смысл иметь ряд NSDictionaryидентификаторов для блоков конструктора для такого идентификатора.
Benjohn 05
11

Вы можете избежать постороннего подкласса, используя построитель интерфейса раскадровки:

  1. В представлении Раскадровка выберите ячейку прототипа ячейки табличного представления (в представлении таблицы)
  2. В представлении «Утилиты» в инспекторе атрибутов измените значение стиля.
  3. (Необязательно) Измените другие значения, такие как Выбор и Аксессуар

Новая iOS 6.0 dequeueReusableCellWithIdentifier:forIndexPath:действительно использует эти значения при выделении новых ячеек и их возврате. (Проверено на компиляции iOS 6.0 с использованием Xcode 4.5.2)

Джефф Коллиер
источник
7

Еще одна альтернатива, позволяющая сохранить один файл, - создать перо и использовать его registerNib:forCellReuseIdentifier:вместо него.

Сделать перо легко: создайте новый файл .xib в Interface Builder. Удалите вид по умолчанию. Добавьте объект Table View Cell. С помощью инспектора атрибутов измените стиль ячейки. (Здесь у вас также есть возможность дополнительно настроить ячейку, настроив другие атрибуты.)

Затем в viewDidLoadметоде контроллера табличного представления вызовите что-то вроде:

[self.tableView registerNib:[UINib nibWithNibName:@"StyleSubtitleTableCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"Cell"];
Г-н Берна
источник
initWithStyle: reuseIdentifier не вызывается.
thierryb 01
0

Ответ Болота правильный. Просто, и вам не нужно создавать файл XIB.

Я просто хотел обновить его ответ для тех, кто делает это, используя Swift вместо Objective-C:

override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: .value1, reuseIdentifier: reuseIdentifier)
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}
Габриэль Олива
источник
-5

Мое решение - позвонить initWithStyle: reuseIdentifier:после того, как я получу его с помощью [self.tableView dequeueReusableCellWithIdentifier:@"cellId" forIndexPath:indexPath]. В конце концов, initэто просто еще один селектор, и компилятор не накладывает ограничений на его вызов для уже инициализированного объекта. Однако он будет жаловаться на то, что не использует результат вызова init, поэтому я делаю:

UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:@"cellId" forIndexPath:indexPath];
cell = [cell initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cellId"];

Я полагаю, это не сработает в Swift ...

Крис
источник
Самое элегантное решение imo. Надеюсь, что внутренности initWithStyle не воссоздают все снова.
Скотт Биркстед,
2
Что ж, я думаю, если вы делаете это вот так, вы можете вообще отказаться от удаления из очереди ...
stk
1
Повторное использование ячеек является ключом к высокопроизводительному UITableView. Ваше решение предлагает не использовать повторно ячейки.
Берик
2
Когда вы вызываете initWithStyle: reuseIdentifierвторой раз, вы фактически перезаписываете ячейку вновь созданным объектом. Да, выделение памяти уже было выполнено, и новая ячейка будет перезаписывать то же самое место в памяти, но на самом деле вы создаете совершенно новый объект, когда снова инициализируете его. Это сводит на нет всю оптимизацию, в которой в первую очередь заключается весь смысл повторного использования ячеек.
AnthonyMDev
1
Не лучшее решение для подражания - если вы используете это решение, я думаю, что, по крайней мере, лучше вообще отказаться от удаления ячеек из
очереди