Reusing blocks on iOS
DivKit reuses blocks during the following events:
- Setting new DivData.
- Scrolling elements in complex containers:
gallery
,grid
,tabs
.
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:
- Check if there is a view for reuse
- Check the
isBestViewForReuse
method to determine if the view is the best candidate for reuse - If the view is not the best candidate, check the
canConfigureBlockView
method - If the view can be reused, update its configuration
- If the view cannot be reused, create a new view
- 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
:
- 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
}
- 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)
}
- 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
- 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.
reuseId
property
Using the 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