Встановлення стилю UITableViewCell при використанні iOS 6 UITableView dequeueReusableCellWithIdentifier: forIndexPath:


82

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

Раніше, створюючи UITableViewCellя, я міняв би UITableViewCellStyleперелік, щоб створювати різні типи клітинок за замовчуванням при виклику, initWithStyle:але з того, що я можу зібрати, це вже не так.

Документація Apple для UITableViewдержав:

Повернене значення : об’єкт UITableViewCell із пов’язаним ідентифікатором повторного використання. Цей метод завжди повертає дійсну комірку.

Обговорення : З міркувань продуктивності джерело даних подання таблиці має, як правило, повторно використовувати об'єкти UITableViewCell, коли воно призначає комірки рядкам у своєму методі tableView: cellForRowAtIndexPath:. У поданні таблиці зберігається черга або список об’єктів UITableViewCell, які джерело даних позначило для повторного використання. Викличте цей метод із об’єкта джерела даних, коли вам буде запропоновано надати нову комірку для подання таблиці. Цей метод дезактивує існуючу комірку, якщо така є, або створює нову на основі файлу класу чи файлу, який ви раніше зареєстрували.

Важливо : Перед викликом цього методу потрібно зареєструвати файл класу чи файл nib, використовуючи метод registerNib: forCellReuseIdentifier: або registerClass: forCellReuseIdentifier:.

Якщо ви зареєстрували клас для вказаного ідентифікатора і потрібно створити нову комірку, цей метод ініціалізує комірку, викликаючи її метод initWithStyle: reuseIdentifier:. Для комірок на основі nib, цей метод завантажує об’єкт комірки із наданого файлу nib. Якщо наявна комірка була доступна для повторного використання, цей метод замість цього викликає метод клітинки PrepaForReuse.

Ось як 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:щоб надати деякі ідентифікатори, які будують комірки по-старому (і повертають їх). Інші ідентифікатори викличуть супер і повернуть це. Може мати сенс мати NSDictionaryідентифікатори для блоків конструктора для такого типу ідентифікатора.
Benjohn

11

Ви можете уникнути сторонніх підкласів, використовуючи конструктор інтерфейсів розкадрування:

  1. У поданні Раскадровки виберіть клітинку прототипу комірки подання таблиці (у поданні таблиці)
  2. У поданні Службові програми в інспекторі Атрибути змініть значення Стиль
  3. (Необов’язково) Змініть інші значення, такі як Вибір та Аксесуар

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


7

Ще однією альтернативою, яка зберігає один файл, є створення Nib та використання registerNib:forCellReuseIdentifier:замість нього.

Зробити перо просто: створіть новий файл .xib у Interface Builder. Видаліть подання за замовчуванням. Додайте об’єкт комірки табличного подання. За допомогою інспектора атрибутів змініть стиль комірки. (Тут ви також маєте можливість додатково налаштувати комірку, налаштувавши інші атрибути.)

Тоді у viewDidLoadметоді контролера подання таблиці викличте щось на зразок:

[self.tableView registerNib:[UINib nibWithNibName:@"StyleSubtitleTableCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"Cell"];

initWithStyle: reuseIdentifier не викликається.
thierryb

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. Ваше рішення пропонує не використовувати клітини повторно.
Berik

2
Коли ви телефонуєте initWithStyle: reuseIdentifierвдруге, ви фактично перезаписуєте клітинку новоствореним об’єктом. Так, розподіл пам’яті вже було зроблено, і нова комірка збирається перезаписати те саме місце пам’яті, але ви фактично створюєте абсолютно новий об’єкт, коли його ініціалізуєте знову. Це заперечує всю оптимізацію, яка полягає в першому сенсі повторного використання клітин.
AnthonyMDev

1
Невдале рішення для наслідування - якщо ви використовуєте це рішення, я думаю, що, принаймні, краще повністю відмовитися від знецірення клітин
Судара,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.