Reusing blocks on iOS

DivKit reuses blocks during the following events:

Reuse when new DivData is set

DivKit always attempts to reuse already created elements. For this purpose, the reuse method of the UIViewRenderable protocol is used, which determines whether a block can be reused.

Reuse process diagram

Below is a diagram of the block reuse process in iOS:

The reuse process includes the following steps:

  1. Check if there is a view for reuse
  2. Check the isBestViewForReuse method to determine if the view is the best candidate for reuse
  3. If the view is not the best candidate, check the canConfigureBlockView method
  4. If the view can be reused, update its configuration
  5. If the view cannot be reused, create a new view
  6. Configure the view and return it

Implementation details of reuse methods

In the block reuse process in DivKit, two key methods are used: canConfigureBlockView and isBestViewForReuse:

  1. canConfigureBlockView - a basic method that checks the UIView type. Its implementation is usually very simple:
// Example for ImageBlock
public func canConfigureBlockView(_ view: BlockView) -> Bool {
  view is RemoteImageViewContainer
}
  1. isBestViewForReuse - for simple blocks (Image, Text) and some composite blocks (Container, Gallery), by default, it simply calls canConfigureBlockView:
// Default implementation in the UIViewRenderable protocol
public func isBestViewForReuse(_ view: BlockView) -> Bool {
  canConfigureBlockView(view)
}
  1. isBestViewForReuse for some complex blocks - for certain composite blocks (e.g., DecoratingBlock), it has more complex logic:
// Example for DecoratingBlock
func isBestViewForReuse(_ view: BlockView) -> Bool {
  guard let view = view as? DecoratingView,
        view.childView != nil else { return false }
  return child.isBestViewForReuse(view.childView!)
}

In this example, isBestViewForReuse not only checks the view type but also:

  • Requires the presence of a non-empty child view
  • Recursively checks if the child view is optimal for reuse
  1. Features of composite blocks - blocks containing collections of child elements (Container, Gallery) delegate the reuse of child elements to a special reused method for arrays:
// In ContainerBlockView
blockViews = blockViews.reused(
  with: model.children.map(\.content),
  attachTo: self,
  observer: observer,
  overscrollDelegate: overscrollDelegate,
  renderingDelegate: renderingDelegate
)

The reused method itself implements a two-level reuse system for each child element.

Reuse in complex containers

In complex containers such as gallery, grid, and tabs, DivKit uses the UIKit collection cell reuse mechanism. Each block has a reuseId property that is used to identify blocks that can be reused.

For example, in GalleryView, the cellForItemAt method uses block.reuseId to get a reusable cell from the collection:

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

By default, reuseId returns the string "DefaultReuseId", but blocks can override this property for more precise control over reuse.

Using the reuseId property

For more efficient reuse of blocks in complex containers, it is recommended to set the reuseId property for blocks with the same structure. This will allow DivKit to reuse views more efficiently.

Example:
{
    "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",
                    ...
                }
            ]
        }
    ]
}

In this example, blocks with the same reuse_id will be reused among themselves. This is especially important for heavy objects such as video to avoid unnecessary recreation.

Learn more

Follow DivKit news in the Telegram channel: http://t.me/divkit_news

You can also discuss topics of interest in the DivKit user community in Telegram: https://t.me/divkit_community_ru

DivKit Repository

Previous
Next