Переиспользование блоков на iOS

Переиспользование блоков в DivKit на iOS происходит при следующих событиях:

Переиспользование при установке новой DivData

DivKit всегда пытается переиспользовать уже созданные элементы. Для этого используется метод reuse протокола UIViewRenderable, который определяет, может ли блок быть переиспользован.

Диаграмма процесса переиспользования

Ниже представлена диаграмма процесса переиспользования блоков в iOS:

Процесс переиспользования включает следующие шаги:

  1. Проверка наличия view для переиспользования
  2. Проверка метода isBestViewForReuse для определения, является ли view лучшим кандидатом для переиспользования
  3. Если view не является лучшим кандидатом, проверка метода canConfigureBlockView
  4. Если view может быть переиспользован, обновление его конфигурации
  5. Если view не может быть переиспользован, создание нового view
  6. Конфигурация view и его возврат

Особенности реализации методов переиспользования

В процессе переиспользования блоков в DivKit используются два ключевых метода: canConfigureBlockView и isBestViewForReuse:

  1. canConfigureBlockView - базовый метод, который проверяет тип UIView. Его реализация обычно очень проста:
// Пример для ImageBlock
public func canConfigureBlockView(_ view: BlockView) -> Bool {
  view is RemoteImageViewContainer
}
  1. isBestViewForReuse - для простых блоков (Image, Text) и некоторых составных блоков (Container, Gallery) по умолчанию просто вызывает canConfigureBlockView:
// Реализация по умолчанию в протоколе UIViewRenderable
public func isBestViewForReuse(_ view: BlockView) -> Bool {
  canConfigureBlockView(view)
}
  1. isBestViewForReuse для некоторых сложных блоков - для определенных составных блоков (например, DecoratingBlock) имеет более сложную логику:
// Пример для DecoratingBlock
func isBestViewForReuse(_ view: BlockView) -> Bool {
  guard let view = view as? DecoratingView,
        view.childView != nil else { return false }
  return child.isBestViewForReuse(view.childView!)
}

В этом примере isBestViewForReuse не только проверяет тип view, но и:

  • Требует наличия непустого дочернего view
  • Рекурсивно проверяет, является ли дочерний view оптимальным для переиспользования
  1. Особенности составных блоков - блоки, содержащие коллекции дочерних элементов (Container, Gallery), делегируют переиспользование дочерних элементов специальному методу reused для массивов:
// В ContainerBlockView
blockViews = blockViews.reused(
  with: model.children.map(\.content),
  attachTo: self,
  observer: observer,
  overscrollDelegate: overscrollDelegate,
  renderingDelegate: renderingDelegate
)

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

Переиспользование в сложных контейнерах

В сложных контейнерах, таких как gallery, grid и tabs, DivKit использует механизм переиспользования ячеек коллекций UIKit. Каждый блок имеет свойство reuseId, которое используется для идентификации блоков, которые могут быть переиспользованы.

Например, в GalleryView метод cellForItemAt использует block.reuseId для получения переиспользуемой ячейки из коллекции:

let cell = collectionView.dequeueReusableCell(
  withReuseIdentifier: block.reuseId,
  for: indexPath
) as! CellType

По умолчанию reuseId возвращает строку "DefaultReuseId", но блоки могут переопределить это свойство для более точного контроля над переиспользованием.

Использование свойства reuse_id

Для более эффективного переиспользования блоков в сложных контейнерах рекомендуется устанавливать свойство reuse_id для блоков с одинаковой структурой. Это позволит DivKit более эффективно переиспользовать представления.

Пример:
{
    "type": "gallery",
    "items": [
        {
            "type": "container",
            "reuse_id": "video_block",
            "items": [
                {
                    "type": "video",
                    ...
                }
            ]
        },
        {
            "type": "container",
            "reuse_id": "image_block",
            "items": [
                {
                    "type": "image",
                    ...
                }
            ]
        },
        {
            "type": "container",
            "reuse_id": "image_block",
            "items": [
                {
                    "type": "image",
                    ...
                }
            ]
        },
        {
            "type": "container",
            "reuse_id": "video_block",
            "items": [
                {
                    "type": "video",
                    ...
                }
            ]
        }
    ]
}

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

Узнать больше

Следите за новостями DivKit в Telegram-канале: http://t.me/divkit_news.

Также вы можете обсуждать интересующие вас темы в сообществе пользователей DivKit в Telegram: https://t.me/divkit_community_ru.

Репозиторий DivKit

Предыдущая
Следующая