Как я могу ускорить UITableView? - PullRequest
16 голосов
/ 30 мая 2011

У меня есть UITableView с примерно 400 ячейками в 200 секциях, и он немного вяло реагирует на взаимодействие с пользователем (прокрутка, выбор ячеек.)работает, и я не думаю, что я делаю что-то необычное, чтобы сделать это медленно.Ячейки и заголовки имеют только фоновое изображение и текст.У кого-нибудь еще была такая проблема, и знаете ли вы какой-нибудь способ заставить ее работать немного быстрее?

Редактировать: Я предлагаю вознаграждение, потому что я хотел бы получитьнекоторые полезные отзывы об этом.Я не думаю, что ответ кроется в проблеме в моем коде.Вместо этого я ищу стратегии реорганизации UITableView, чтобы он работал быстрее.Я полностью готов к добавлению нового кода и с нетерпением ожидаю услышать, что вы, ребята, должны сказать.

Вялость наблюдается и на симуляторе, и на моем устройстве iPhone 4. Вот мои реализации viewForHeaderInSection и cellForRowAtIndexPath, которые являются единственными UITableViewDelegate методами, реализованными нетривиально.Я повторно использую ячейки и представления заголовка.

- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger) section
{
    HaikuHeaderView* view= [m_sectionViews objectAtIndex:section];
    NSMutableArray* array= [m_haikuSearch objectAtIndex:section];
    Haiku* haiku= [array objectAtIndex:0];

    [view.poetLabel setText:[haiku nameForDisplay]];

    return view;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];

        cell.backgroundView= [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cell gradient2.png"]];

        // (Set up a bunch of label attributes in the cell...)
    }

    NSMutableArray* array= [m_haikuSearch objectAtIndex:indexPath.section];
    Haiku* haiku = [array objectAtIndex:indexPath.row];
    cell.textLabel.text = [haiku.m_lines objectAtIndex:0];

    return cell;
}

Ответы [ 9 ]

48 голосов
/ 23 июня 2011

Даже если ваша клетка на самом деле такая простая (фоновое изображение и метка), есть некоторые вещи, на которые стоит обратить внимание

Кэширование изображений Это очевидная вещь - если вы используете одно и то же изображение везде, загрузите его один раз в UIImage и используйте его повторно. Даже если система сама кеширует ее, прямое использование уже загруженной не должно повредить.

Быстрый расчет Еще одна довольно очевидная вещь - сделать подсчет высоты и содержания максимально быстрым. Не выполняйте синхронные выборки (сетевые вызовы, чтение с диска и т. Д.).

Альфа-канал в изображении Что дорого при рисовании - это прозрачность. Поскольку фон вашей ячейки ничего не скрывает, убедитесь, что вы сохранили изображение без альфа-канала. Это экономит много времени на обработку.

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

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

Проверка композитинга В симуляторе есть инструмент для выделения деталей, которые рендерится дорого из-за прозрачности (зеленый в порядке, красный - в альфа-смешении). Его можно найти в меню отладки: «Цветные смешанные слои»

9 голосов
/ 21 июня 2011

Лучшее, что вы можете сделать, если хотите ускорить свой код, - это профилировать его. Для этого есть две причины:

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

  2. Невозможно знать, действительно ли изменения, которые вы вносите в попытке ускорить процесс, будут иметь значение, если у вас нет чисел, которые можно было бы измерить. Если вы можете показать, что ваш код тратит 80% своего времени на одну процедуру, а вы сократили его до 35%, вы знаете, что делаете успехи.

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

5 голосов
/ 30 мая 2011

Просто обратите внимание на эти моменты ..

  1. Используете ли вы ячейки повторно .. Что является хорошей практикой ...
  2. Убедитесь, что вы не выполняете дорогостоящие вычисления вОбратный вызов cellForRowAtIndexPath или в функции, вызываемой из CellForRowAtIndexPath ..
  3. Вы сказали, что есть фоновое изображение.Другая причина, по которой вы должны повторно использовать вашу ячейку.

Хорошая информация о повторном использовании ячейки: здесь ..

РЕДАКТИРОВАТЬ: Найдена на этой странице очень поздно..

Этот ТАК вопрос может помочь вам ... особенно принятый ответ ...

3 голосов
/ 22 июня 2011
  1. использовать экземпляр общего изображения для фона (вы выделяете / инициализируете / освобождаете его каждый раз при создании новой ячейки). Если у вас большое табличное представление, это означает, что фоновые X-ячейки в памяти занимают гораздо больше памяти, чем должны.

    вместо
    cell.backgroundView= [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cell gradient2.png"]];
    просто используйте:
    cell.backgroundView= [SomeHelperClass sharedBackgroundUIImageResource];

  2. Если это не поможет, используйте CG вместо меток и других подпредставлений (скриншот поможет здесь ... узнать, о чем мы говорим).

2 голосов
/ 30 мая 2011

Реализует ли делегат табличного представления:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

Если это так, вы можете рассмотреть возможность установки свойства rowHeight вашего UITableViewCell.

1 голос
/ 21 июня 2011

Два предложения: Один из них - использовать -initWithStyle:reuseIdentifier: для ячеек табличного представления вместо -initWithFrame :. Другой - закомментировать установку cell.backgroundView для изображения с градиентом и посмотреть, является ли это виновником. Каждый раз, когда у меня была плохая производительность в табличном представлении, это было из-за изображения.

1 голос
/ 21 июня 2011

Вы используете много подпредставлений?

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

Для этого вам нужно создать подкласс UITableViewCell и реализовать метод -(void)drawRect:(CGRect)rect.

0 голосов
/ 27 июня 2015

Это немного не по теме (потому что у вас есть только одно фоновое изображение для всех ячеек):

Мое приложение отображает разные изображения в каждой ячейке.После добавления около 5 ячеек в UITableView - таблица резко замедляется.Обработка всех изображений занимает около 1-2 секунд каждый раз, когда я открываю контроллер вида.

if let image = UIImage(contentsOfFile: photoFile){
    // just set it and let system fit it
    //cell.imageView!.image = image

    // 1 - Calculate sized
    let DEFAULT_THUMBNAIL_WIDTH: CGFloat  = (cellHeight / 4) * 5;
    let DEFAULT_THUMBNAIL_HEIGHT: CGFloat = cellHeight;

    let aspectRatio: CGFloat = image.size.width / image.size.height
    var willBeHeight = DEFAULT_THUMBNAIL_HEIGHT
    var willBeWidth  = DEFAULT_THUMBNAIL_HEIGHT * aspectRatio

    if(willBeWidth > DEFAULT_THUMBNAIL_WIDTH){
        willBeWidth = DEFAULT_THUMBNAIL_WIDTH
        willBeHeight = willBeWidth / aspectRatio
    }

    let eps:CGFloat = 0.000001
    assert((willBeHeight - eps) <= DEFAULT_THUMBNAIL_HEIGHT);
    assert((willBeWidth - eps) <= DEFAULT_THUMBNAIL_WIDTH);

    // 2 - Create context
    var size:CGSize = CGSize(
        width: DEFAULT_THUMBNAIL_WIDTH,
        height: DEFAULT_THUMBNAIL_HEIGHT)
    UIGraphicsBeginImageContext(size)

    // one-to-one rect
    //var imageRect: CGRect = CGRectMake(0.0, 0.0, size.width, size.height)
    var imageRect: CGRect = CGRectMake(0.0, 0.0, willBeWidth, willBeHeight)

    // 3 - Draw image
    image.drawInRect(imageRect)
    var imageResult: UIImage = UIGraphicsGetImageFromCurrentImageContext()
    cell.imageView!.image = imageResult

    UIGraphicsEndImageContext()
}else{
    DDLogError("Can not draw photo: \(photoFile)")
}

Так что я закончил с созданием маленьких THUMBNAILS для всех моих изображений.

0 голосов
/ 22 июля 2011

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

...