Я могу создавать собственные UITableViewCells и загружать их просто так, используя технику, описанную в потоке, найденном в http://forums.macrumors.com/showthread.php?t=545061. Однако использование этого метода больше не позволяет вам инициализировать ячейку с reuseIdentifier, что означает, что вам нужно создавать совершенно новые экземпляры каждой ячейки при каждом вызове. Кто-нибудь придумал хороший способ по-прежнему кэшировать определенные типы ячеек для повторного использования, но при этом иметь возможность создавать их в Interface Builder?





Просто реализуйте метод с соответствующей сигнатурой метода:
- (NSString *) reuseIdentifier {
return @"myIdentifier";
}
В вашем подклассе UITableViewCell. developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Referen ce /…
Это рискованно. Что произойдет, если у вас есть два подкласса подкласса ячейки, и вы используете оба из них в одном табличном представлении? Если они отправят вызов идентификатора повторного использования на super, вы удалите из очереди ячейку неправильного типа .............. Я думаю, вам нужно переопределить метод reuseIdentifier, но он вернет замененный идентификатор нить.
Чтобы убедиться, что он уникален, вы можете сделать: return NSStringFromClass([self class]);
Как бы то ни было, я спросил об этом инженера по iPhone на одном из iPhone Tech Talks. Его ответ был: «Да, можно использовать IB для создания ячеек. Но не надо. Пожалуйста, не надо».
Странно. По крайней мере, в двух выступлениях на конференции в Нью-Йорке был демонстрационный код, в котором использовались ячейки, созданные в IB.
Не уверен, что верю в это, поскольку они используют IB для создания ячеек в примере проекта Apple Advanced Table View Cells.
Спасибо за это. Каждый раз, когда я это делал, я сталкивался с проблемами. Это могло быть почему
Вероятно, он не знал об этом достаточно.
Взгляните на ответ, который я дал на этот вопрос:
Возможно ли проектировать подклассы NSCell в Интерфейсном Разработчике?
UITableViewCell можно не только спроектировать в IB, но и желательно, потому что в противном случае вся ручная разводка и размещение нескольких элементов очень утомительна. Исполнение в порядке, если вы стараетесь сделать все элементы непрозрачными, когда это возможно. Идентификатор повторного использования устанавливается в IB для свойств UITableViewCell, затем вы используете соответствующий идентификатор повторного использования в коде при попытке удаления из очереди.
Я также слышал от некоторых докладчиков на WWDC в прошлом году, что вы не должны создавать ячейки табличного представления в IB, но это полная чушь.
Вы не должны создавать ячейки табличного представления в IB, если вам нужна прозрачность и хорошая производительность прокрутки. Для определенных пользовательских интерфейсов вам нужна прозрачность (например, для визуализации текста поверх графики). Иногда единственный способ добиться хорошей прокрутки на старом оборудовании (до A4) - это выполнить рендеринг в коде, чтобы графическому процессору не приходилось объединять несколько прозрачных слоев.
Верно, но даже при этом вам может быть лучше позволить немного снизить производительность на старых устройствах, чтобы упростить обслуживание ячеек, встроенных в IB. Вы также можете использовать этот метод в качестве ячейки шаблона, из которой вы затем рисуете элементы, чтобы избежать компоновки с помощью специального метода рисования.
У меня сработал метод Луи. Это код, который я использую для создания UITableViewCell из пера:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"CustomCellId"];
if (cell == nil)
{
UIViewController *c = [[UIViewController alloc] initWithNibName:@"CustomCell" bundle:nil];
cell = (PostCell *)c.view;
[c release];
}
return cell;
}
Фактически, поскольку вы создаете ячейку в Интерфейсном Разработчике, просто установите там идентификатор повторного использования:
Или, если вы используете Xcode 4, проверьте вкладку инспектора атрибутов:

(Обновлено: после того, как ваш XIB сгенерирован XCode, он содержит пустой UIView, но нам нужен UITableViewCell; поэтому вам нужно вручную удалить UIView и вставить ячейку представления таблицы. Конечно, IB не будет отображать какие-либо параметры UITableViewCell для UIView.)
Что мне установить идентификаторы, если я использую эти созданные пером ячейки для более чем одной ячейки? В результате мы получим две ячейки с одинаковыми идентификаторами.
Не думайте об этом как об уникальном идентификаторе - думайте о нем больше как об имени типа.
Я не вижу возможности установить идентификатор через встроенный построитель интерфейса в Xcode 4.3.3. Я определенно устанавливаю класс для своего подкласса UITableViewCell. Я просто скучаю по нему или его больше нет?
Хорошо, я решил свою проблему. Если вы начнете с объекта UIView в построителе интерфейса (в Xcode 4) и измените его класс на UITableViewCell, вы не получите специфичных для ячейки свойств, таких как идентификатор повторного использования. Чтобы получить это, вы должны начать с пустого xib и перетащить объект ячейки таблицы, который затем будет иметь свойства, специфичные для ячейки, которые вы можете редактировать.
@Krishnan Подумайте об этом так - когда вы создаете ячейку табличного представления с идентификатором X, вы говорите: «Дайте мне ячейку из пула с меткой X». Если пул существует, и в нем есть свободная ячейка, то он отдает ее вам. В противном случае он создает пул (при необходимости), затем обновляет ячейку, маркирует ее «X» и передает ее вам. Таким образом, клетки МОГУТ быть уникальными - например, вы можете создать пул только с одной ячейкой с определенным идентификатором, но библиотека использует стратегию бесплатного списка, чтобы избежать выделения / освобождения памяти.
@Tyler только что проверил это в XCode 5, и он есть, поэтому я предполагаю, что да в 4.3.3.
Я не могу вспомнить, где я изначально нашел этот код, но до сих пор он отлично работал у меня.
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"CustomTableCell";
static NSString *CellNib = @"CustomTableCellView";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:CellNib owner:self options:nil];
cell = (UITableViewCell *)[nib objectAtIndex:0];
}
// perform additional custom work...
return cell;
}
Пример настройки Interface Builder ...
Я создаю свои настраиваемые ячейки просмотра аналогичным образом, за исключением того, что подключаю ячейку через IBOutlet.
Подход [nib objectAt...] чувствителен к изменениям позиций элементов в массиве.
Подход UIViewController хорош - просто попробовал, и он неплохо работает.
НО...
Во всех случаях конструктор initWithStyle НЕ вызывается, поэтому инициализация по умолчанию не выполняется.
Я читал в разных местах об использовании initWithCoder или awakeFromNib, но не имел убедительных доказательств того, что любой из этих способов является правильным.
Кроме явного вызова некоторого метода инициализации в методе cellForRowAtIndexPath, я еще не нашел на это ответа.
awakeFromNib - это правильный способ реагировать на объект, загружаемый из NIB.
Некоторое время назад я нашел отличное сообщение в блоге по этой теме на blog.atebits.com, и с тех пор начал использовать класс Loren Brichter ABTableViewCell для всех моих UITableViewCells.
В итоге вы получаете простой контейнер UIView для размещения всех ваших виджетов, а прокрутка выполняется молниеносно.
Надеюсь, это будет полезно.
Решение gustavogb у меня не работает, я пробовал:
ChainesController *c = [[ChainesController alloc] initWithNibName:@"ChainesController" bundle:nil];
[[NSBundle mainBundle] loadNibNamed:@"ChaineArticleCell" owner:c options:nil];
cell = [c.blogTableViewCell retain];
[c release];
Вроде работает. BlogTableViewCell - это IBOutlet для ячейки, а ChainesController - владелец файла.
Этот метод также работает и не требует фанкового ivar в вашем контроллере представления для управления памятью. Здесь ячейка настраиваемого табличного представления находится в xib-файле с именем «CustomCell.xib».
static NSData *sLoadedCustomCell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:@"CustomCell"];
if (cell == nil)
{
if (sLoadedCustomCell == nil)
{
// Load the custom table cell xib
// and extract a reference to the cell object returned
// and cache it in a static to avoid reloading the nib again.
for (id loadedObject in [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:nil options:nil])
{
if ([loadedObject isKindOfClass:[UITableViewCell class]])
{
sLoadedCustomCell = [[NSKeyedArchiver archivedDataWithRootObject: loadedObject] retain];
break;
}
}
cell = (UITableViewCell *)[NSKeyedUnarchiver unarchiveObjectWithData: sLoadedCustomCell];
}
В архивировании и разархивировании нет необходимости.
В архивировании / разархивировании нет необходимости, если вы нормально загружаете ячейку из ее пера, когда она не может быть удалена из очереди. Однако, если вы хотите загрузить ячейку только из ее пера точно однажды, вам необходимо кэшировать ее в памяти. Я выполняю это кеширование с помощью NSKeyedArchiving, потому что UITableViewCell не реализует NSCopying.
При этом использование UINib для загрузки ячейки дает тот же эффект: загрузка с диска один раз, а затем загрузка из памяти.
Начиная с iOS около 4.0, в документации iOS есть специальные инструкции, которые делают эту работу сверхбыстрой:
Прокрутите вниз до того места, где говорится о создании подкласса от UITableViewCell.
Я следовал инструкциям Apple, по ссылке Бена Мошера (спасибо!), Но обнаружил, что Apple упустила важный момент. Объект, который они создают в IB, - это просто UITableViewCell, как и переменная, которую они загружают из него. Но если вы на самом деле настроите его как настраиваемый подкласс UITableViewCell и напишете файлы кода для подкласса, вы можете написать объявления IBOutlet и методы IBAction в коде и связать их со своими настраиваемыми элементами в IB. Тогда нет необходимости использовать теги просмотра для доступа к этим элементам, и вы можете создать любую сумасшедшую ячейку, какую захотите. Это рай какао Touch.
Из документов UITableView относительно dequeueWithReuseIdentifier: «Строка, идентифицирующая объект ячейки, который будет использоваться повторно. По умолчанию идентификатором повторно используемой ячейки является имя ее класса, но вы можете изменить его на любое произвольное значение».
Самостоятельная переопределение -reuseIdentifer рискованно. Что произойдет, если у вас есть два подкласса подкласса ячейки, и вы используете оба из них в одном табличном представлении? Если они отправят вызов идентификатора повторного использования на super, вы удалите из очереди ячейку неправильного типа .............. Я думаю, вам нужно переопределить метод reuseIdentifier, но он вернет замененный идентификатор нить. Или, если он не был указан, вернуть класс в виде строки.
Вот еще один вариант:
NSString * cellId = @"reuseCell";
//...
NSArray * nibObjects = [[NSBundle mainBundle] loadNibNamed:@"CustomTableCell" owner:nil options:nil];
for (id obj in nibObjects)
{
if ([obj isKindOfClass:[CustomTableCell class]])
{
cell = obj;
[cell setValue:cellId forKey:@"reuseIdentifier"];
break;
}
}
Обратите внимание, что это единственное решение, опубликованное на данный момент, которое не требует подкласса вашего пользовательского UITableViewCell, чтобы установить уникальное значение для reuseIdentifer. Я думаю, это именно то, что искала оригинальная операция.
Я надеюсь, что Apple не откажет моему приложению в использовании этого ... Я использую это для получения «статических» ячеек, потому что в моем табличном представлении процесс заполнения ячейки довольно медленный. Таким образом, мне просто нужно выполнить его один раз (давая разные идентификаторы каждой строке). Спасибо!
Очень полезно, так как не существует метода UITableViewCell для ручной настройки!
Теперь в iOS 5 для этого есть подходящий метод UITableView:
- (void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier
Другие ответы в этой ветке, включая принятый ответ, содержат устаревшие рекомендации.
это обратно совместимо? Я имею в виду, что если я разрабатываю приложение с SDK 5.0 и целевой минимум 4.0, будет ли приложение работать, например, на устройствах с iOS 4.0?
Нет, это не имеет обратной совместимости, как любой новый API в iOS 5.0.
рабочий пример того, как интегрировать это в ваш контроллер: mindfiresolutions.com/…
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = @"CustomCell";
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
}
return cell;
}
Где реализовать этот метод?