---
title: UICollectionView Challenges
layout: docs
permalink: /docs/uicollectionview-challenges.html
---
`UICollectionView` is one of the most commonly used classes and many challenges with iOS development are related to its architecture.
## How `UICollectionView` Works
There are two important methods that `UICollectionView` requires.
Cell Measurement
For each item in the data source, the collection must know its size to understand which items should be visible at a given momement. This is provided by:
SwiftObjective-C
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
optional func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize
Although not formally named by Apple, we refer to this process as "measuring". Implementing this method is always difficult, because the view that implements the cell layout is never available at the time of this method call.
This means that logic must be duplicated between the implementation of this method and the `-layoutSubviews` implementation of the cell subclass. This presents a tremendous maintainence burden, as the implementations must always match their behavior for any combination of content displayed.
Additionally, once measurement is complete, there's no easy way to cache that information to use it during the layout process. As a result, expensive text measurements must be repeated.
Cell Allocation
Once an item reaches the screen, a view representing it is requested:
SwiftObjective-C
- (UICollectionViewCell *)cellForItemAtIndexPath:(NSIndexPath *)indexPath;
func cellForItem(at indexPath: IndexPath) -> UICollectionViewCell?
In order to provide a cell, all subviews must be configured with the data that they are intended to display. Immediately afterwards, the layout of the cell is calculated, and finally the display (rendering) of the individual elements (text, images) contained within.
For those who are curious, this extremely detailed
diagram shows the full process of
UICollectionView
communicating with its data source and delegate to display itself.
Limitations in `UICollectionView`'s Architecture
There are several issues with the architecture outlined above:
Lots of main thread work, which may degrade the user's experience, including
- cell measurement
- cell creation + setup / reuse
- layout
- display (rendering)
Duplicated layout logic
You must have duplicate copies of your cell sizing logic for the cell measurement and cell layout stages. For example, if you want to add a price tag to your cell, both -sizeForItemAtIndexPath
and the cell's own -layoutSubviews
must be aware of how to size the tag.
No automatic content loading
There is no easy, universal way to handle loading content such as:
- data pages - such as JSON fetching
- other info - such as images or secondary JSON requests
## How `ASCollectionNode` works
Unified Cell Measurement & Allocation
Texture takes both of the important collection methods explained above:
SwiftObjective-C
- (UICollectionViewCell *)cellForItemAtIndexPath:(NSIndexPath *)indexPath;
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
optional func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize
func cellForItem(at indexPath: IndexPath) -> UICollectionViewCell?
and replaces them with a single method*:
SwiftObjective-C
- (ASCellNode *)collectionNode:(ASCollectionNode *)collectionNode nodeForItemAtIndexPath:(NSIndexPath *)indexPath;
func collectionNode(collectionNode: ASCollectionNode, nodeForItemAtIndexPath indexPath: NSIndexPath) -> ASCellNode
or with the asynchronous versions
SwiftObjective-C
- (ASCellNodeBlock)collectionNode:(ASCollectionNode *)collectionNode nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath;
func collectionNode(collectionNode: ASCollectionNode, nodeBlockForItemAtIndexPath indexPath: NSIndexPath) -> ASCellNodeBlock
*Note that there is an optional method to provide a constrained size for the cell, but it is not needed by most apps.
ASCellNode
, is Texture's universal cell class. They are light-weight enough to be created an an earlier time in the program (concurrently in the background) and they understand how to calculate their own size. `ASCellNode` automatically caches its measurement so that it can be quickly applied during the layout pass.
As a comparison to the diagram above, this detailed
diagram shows the full process of an
ASCollectionView
communicating with its data source and delegate to display itself.. Note that
ASCollectionView
is
ASCollectionNode
's underlying
UICollectionView
subclass.
Benefits of Texture's Architecture
Elimination of all of the types of main thread work described above (cell allocation, measurement, layout, display)! In addition, all of this work is preformed concurrently on multiple threads.
Because `ASCollectionNode` is aware of the position of all of its nodes, it can automatically determine when content loading is needed. The Batch Fetching API handles loading of data pages (like JSON) and Intelligent Preloading automatically manages the loading of images and text. Additionally, convenient callbacks allow implementing accurate visibility logging and secondary data model requests.
Lastly, almost all of the concepts we've discussed here apply to `UITableView` / `ASTableNode` and `UIPageViewController` / `ASPagerNode`.
## iOS 10 Cell Pre-fetching
Inspired by Texture, iOS 10 introduced a cell pre-fetching. This API increases the number of cells that the collection tracks at any given time, which helps, but isn't anywhere as performance centric as being aware of all cells in the data source.
Additionally, iOS9 still constitutes a substantial precentage of most app's userbase and will not reduce in number anywhere close to as quickly as the sunset trajectory of iOS 7 and iOS 8 devices. Whereas iOS 9 is the last supported version for about a half-dozen devices, there were zero devices that were deprecated on iOS 8 and only one deivce deprecated on iOS 7.
Unfortunately, these iOS 9 devices are the ones in which performance is most key!