Копирование UITableViewCell - PullRequest
       10

Копирование UITableViewCell

7 голосов
/ 20 февраля 2009

Я читаю пользовательскую ячейку таблицы в tableView:cellForRowAtIndexPath: из файла пера. Это прекрасно работает для моих целей, за исключением того, что это довольно медленно.

Теперь я знаю, что в долгосрочной перспективе правильно создать ячейку полностью в коде, использовать одно представление и так далее. Но это прототип, и я не хочу вкладывать в него столько усилий.

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

Вот что я использую для загрузки пера, который я называю с viewDidLoad:retain после)

-(id)loadFromNamed:(NSString*)name {
    NSArray *objectsInNib = [[NSBundle mainBundle] loadNibNamed:name
                                                          owner:self
                                                        options:nil];
    assert( objectsInNib.count == 1 );
    return [objectsInNib objectAtIndex:0];
}

Пока все хорошо. Но вопрос в том, как мне копировать это снова и снова? Это вообще возможно?

Я пробовал [_cachedObject copy] и [_cachedObject mutableCopy], но UITableViewCell не поддерживает ни один из протоколов копирования.

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

Есть идеи?

Ответы [ 5 ]

8 голосов
/ 17 марта 2011

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

UITableViewCell не соответствует протоколу NSCopying, но поддерживает механизм архивирования / разархивирования с ключом, поэтому его можно использовать для клонирования.

На основании ответа " Как дублировать UIButton в Objective C?"мой метод делегата источника данных выглядит так:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellID = @"CellIdentifier";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellID];

    if (!cell) {
        NSData *archivedData = [NSKeyedArchiver archivedDataWithRootObject:self.tableViewCell];
        cell = [NSKeyedUnarchiver unarchiveObjectWithData:archivedData];
    }

    // ... config ...

    return cell;
}

И в моем случае self.tableViewCell - это ячейка, которая была загружена один раз из файла nib представления.

Я не проверял, что будет быстрее: «архив + разархивировать» для клонирования или «загрузить файл пера + разархивировать», что будет делать фреймворк в случае -loadNibNamed: owner: options: , I использовал этот метод только из соображений удобства, но есть хорошие шансы, что операция с памятью и работа с файлами будет быстрее.

РЕДАКТИРОВАТЬ: Кажется, не так просто, как казалось на первый взгляд. Поскольку UIImage не соответствует NSCoding, ячейки с настроенными UIImageViews не могут быть просто скопированы без дополнительного кода. Да, копирование всего изображения определенно не является хорошей практикой, приветствует Apple за указание на это.

6 голосов
/ 21 февраля 2009

Используйте клонирование ячеек, встроенное в табличное представление. Apple знала, что генерация большого количества ячеек таблицы была медленной. Проверьте документы для этого метода:

- (UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier

Вы создаете ячейку один раз, затем при запросе новых ячеек используйте этот метод для клонирования существующих ячеек. Затем вы просто меняете то, что нужно изменить в новой ячейке, и возвращаете объект ячейки.

Также ознакомьтесь с табличным представлением примера кода, предоставленного Apple, который использует этот метод, и покажите вам правильный путь. Тот факт, что ваша клетка была загружена из пера, не имеет никакого значения.


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

4 голосов
/ 08 декабря 2009

Не горжусь этим решением, но оно работает с максимальным числом возможных привязок IB:

Интерфейс (AlbumTableViewCell является подклассом UITableViewCell, экземпляр которого определен в файле XIB AlbumViewController):

@interface AlbumsViewController : UITableViewController {
    IBOutlet AlbumTableViewCell *tableViewCellTrack;
}

@property (nonatomic, retain) AlbumTableViewCell *tableViewCellTrack;

Реализация (архивация / архив делает копию / клонирует ячейку табличного представления):

@implementation AlbumsViewController

@synthesize tableViewCellTrack;

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    AlbumTableViewCell *cell = (AlbumTableViewCell *)[tableView dequeueReusableCellWithIdentifier: @"AlbumCell"];

    if (cell == nil) {
        AlbumsViewController *albumsViewController = [[[AlbumsViewController alloc] init] autorelease];
        [[NSBundle mainBundle] loadNibNamed: @"AlbumsViewController" owner: albumsViewController options: nil];

        cell = albumsViewController.tableViewCellTrack;
    }

    cell.labelTitle.text = ...;
    cell.labelArtist.text = ...;

    return cell;
}
3 голосов
/ 17 июня 2009

Ну, я не уверен, почему во всех руководствах этот шаг не указан.

При использовании вашего собственного пользовательского UITableViewCell из Nib, вызова dequeueReusableCellWithIdentifier недостаточно. Вы должны указать «Идентификатор» в IB, только для этого в разделе вкладки Ячейка табличного представления.

Затем убедитесь, что идентификатор, который вы вводите в IB, совпадает с идентификатором, который вы используете для dequeueReusableCellWithIdentifier.

1 голос
/ 24 октября 2015

Вот оно в Свифте

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    var cell : UITableViewCell?
    let cellId = String(format: "Cell%d", indexPath.row)
    cell = alertTable!.dequeueReusableCellWithIdentifier(cellId) as! UITableViewCell?

    if cell == nil {
        let archivedData = NSKeyedArchiver.archivedDataWithRootObject(masterTableCell!)
        cell = NSKeyedUnarchiver.unarchiveObjectWithData(archivedData) as! UITableViewCell?
    }

    // do some stuff

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