IGListKit/docs/getting-started.html
Tim Oliver 894c34db05 Updated the IGListKit docs to v5.2.0 (#1656)
Summary:
## Changes in this pull request

Updates the IGListKit docs to the latest API spec in v5.2.0

### Checklist

- [x] All tests pass. Demo project builds and runs.
- [x] I added tests, an experiment, or detailed why my change isn't tested.
- [x] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [x] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/main/.github/CONTRIBUTING.md)

Pull Request resolved: https://github.com/instagram/IGListKit/pull/1656

Reviewed By: jurmarcus

Differential Revision: D93350284

Pulled By: TimOliver

fbshipit-source-id: fa4276caae7309f3ef0fd78f5a0c4bcc05d9cb9f
2026-02-16 23:54:31 -08:00

475 lines
32 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<title>Getting Started Reference</title>
<link rel="stylesheet" type="text/css" href="css/jazzy.css" />
<link rel="stylesheet" type="text/css" href="css/highlight.css" />
<meta charset='utf-8'>
<script src="js/jquery.min.js" defer></script>
<script src="js/jazzy.js" defer></script>
<script src="js/lunr.min.js" defer></script>
<script src="js/typeahead.jquery.js" defer></script>
<script src="js/jazzy.search.js" defer></script>
</head>
<body>
<a title="Getting Started Reference"></a>
<header>
<div class="content-wrapper">
<p><a href="index.html">IGListKit 5.2.0 Docs</a> (96% documented)</p>
<p class="header-right"><a href="https://github.com/Instagram/IGListKit"><img src="img/gh.png" alt="GitHub"/>View on GitHub</a></p>
<div class="header-right">
<form role="search" action="search.json">
<input type="text" placeholder="Search documentation" data-typeahead>
</form>
</div>
</div>
</header>
<div class="content-wrapper">
<p id="breadcrumbs">
<a href="index.html">IGListKit</a>
<img id="carat" src="img/carat.png" alt=""/>
<a href="Guides.html">Guides</a>
<img id="carat" src="img/carat.png" alt=""/>
Getting Started Reference
</p>
</div>
<div class="content-wrapper">
<nav class="sidebar">
<ul class="nav-groups">
<li class="nav-group-name">
<a href="Guides.html">Guides</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a href="best-practices-and-faq.html">Best Practices and FAQ</a>
</li>
<li class="nav-group-task">
<a href="generating-your-models-using-remodel.html">Generating your models using remodel</a>
</li>
<li class="nav-group-task">
<a href="getting-started.html">Getting Started</a>
</li>
<li class="nav-group-task">
<a href="iglistdiffable-and-equality.html">IGListDiffable and Equality</a>
</li>
<li class="nav-group-task">
<a href="installation.html">Installation</a>
</li>
<li class="nav-group-task">
<a href="migration.html">Migration</a>
</li>
<li class="nav-group-task">
<a href="modeling-and-binding.html">Modeling and Binding</a>
</li>
<li class="nav-group-task">
<a href="vision.html">VISION</a>
</li>
<li class="nav-group-task">
<a href="working-with-core-data.html">Working with Core Data</a>
</li>
<li class="nav-group-task">
<a href="working-with-uicollectionview.html">Working with UICollectionView</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a href="Categories.html">Categories</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a href="Categories/UIViewController%28IGListAdapter%29.html">UIViewController(IGListAdapter)</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a href="Classes.html">Classes</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a href="Classes/IGListAdapter.html">IGListAdapter</a>
</li>
<li class="nav-group-task">
<a href="Classes/IGListAdapterDelegateAnnouncer.html">IGListAdapterDelegateAnnouncer</a>
</li>
<li class="nav-group-task">
<a href="Classes/IGListAdapterUpdater.html">IGListAdapterUpdater</a>
</li>
<li class="nav-group-task">
<a href="Classes/IGListBatchUpdateData.html">IGListBatchUpdateData</a>
</li>
<li class="nav-group-task">
<a href="Classes/IGListBindingSectionController.html">IGListBindingSectionController</a>
</li>
<li class="nav-group-task">
<a href="Classes/IGListBindingSingleSectionController.html">IGListBindingSingleSectionController</a>
</li>
<li class="nav-group-task">
<a href="Classes/IGListCollectionView.html">IGListCollectionView</a>
</li>
<li class="nav-group-task">
<a href="Classes/IGListCollectionViewLayout.html">IGListCollectionViewLayout</a>
</li>
<li class="nav-group-task">
<a href="Classes/IGListCollectionViewLayoutInvalidationContext.html">IGListCollectionViewLayoutInvalidationContext</a>
</li>
<li class="nav-group-task">
<a href="Classes/IGListGenericSectionController.html">IGListGenericSectionController</a>
</li>
<li class="nav-group-task">
<a href="Classes/IGListIndexPathResult.html">IGListIndexPathResult</a>
</li>
<li class="nav-group-task">
<a href="Classes/IGListIndexSetResult.html">IGListIndexSetResult</a>
</li>
<li class="nav-group-task">
<a href="Classes/IGListMoveIndex.html">IGListMoveIndex</a>
</li>
<li class="nav-group-task">
<a href="Classes/IGListMoveIndexPath.html">IGListMoveIndexPath</a>
</li>
<li class="nav-group-task">
<a href="Classes.html#/c:objc(cs)IGListReloadDataUpdater">IGListReloadDataUpdater</a>
</li>
<li class="nav-group-task">
<a href="Classes/IGListSectionController.html">IGListSectionController</a>
</li>
<li class="nav-group-task">
<a href="Classes/IGListSingleSectionController.html">IGListSingleSectionController</a>
</li>
<li class="nav-group-task">
<a href="Classes/IGListTransitionData.html">IGListTransitionData</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a href="Constants.html">Constants</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a href="Constants.html#/c:@IGListKitVersionNumber">IGListKitVersionNumber</a>
</li>
<li class="nav-group-task">
<a href="Constants.html#/c:@IGListKitVersionString">IGListKitVersionString</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a href="Enums.html">Enumerations</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a href="Enums/IGListAdapterUpdateType.html">IGListAdapterUpdateType</a>
</li>
<li class="nav-group-task">
<a href="Enums/IGListDiffOption.html">IGListDiffOption</a>
</li>
<li class="nav-group-task">
<a href="Enums/IGListExperiment.html">IGListExperiment</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a href="Protocols.html">Protocols</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a href="Protocols/IGListAdapterDataSource.html">IGListAdapterDataSource</a>
</li>
<li class="nav-group-task">
<a href="Protocols/IGListAdapterDelegate.html">IGListAdapterDelegate</a>
</li>
<li class="nav-group-task">
<a href="Protocols/IGListAdapterMoveDelegate.html">IGListAdapterMoveDelegate</a>
</li>
<li class="nav-group-task">
<a href="Protocols/IGListAdapterPerformanceDelegate.html">IGListAdapterPerformanceDelegate</a>
</li>
<li class="nav-group-task">
<a href="Protocols/IGListAdapterUpdateListener.html">IGListAdapterUpdateListener</a>
</li>
<li class="nav-group-task">
<a href="Protocols/IGListAdapterUpdaterDelegate.html">IGListAdapterUpdaterDelegate</a>
</li>
<li class="nav-group-task">
<a href="Protocols/IGListBatchContext.html">IGListBatchContext</a>
</li>
<li class="nav-group-task">
<a href="Protocols/IGListBindable.html">IGListBindable</a>
</li>
<li class="nav-group-task">
<a href="Protocols/IGListBindingSectionControllerDataSource.html">IGListBindingSectionControllerDataSource</a>
</li>
<li class="nav-group-task">
<a href="Protocols/IGListBindingSectionControllerSelectionDelegate.html">IGListBindingSectionControllerSelectionDelegate</a>
</li>
<li class="nav-group-task">
<a href="Protocols/IGListCollectionContext.html">IGListCollectionContext</a>
</li>
<li class="nav-group-task">
<a href="Protocols/IGListCollectionViewDelegateLayout.html">IGListCollectionViewDelegateLayout</a>
</li>
<li class="nav-group-task">
<a href="Protocols/IGListCollectionViewLayoutCompatible.html">IGListCollectionViewLayoutCompatible</a>
</li>
<li class="nav-group-task">
<a href="Protocols/IGListDiffable.html">IGListDiffable</a>
</li>
<li class="nav-group-task">
<a href="Protocols/IGListDisplayDelegate.html">IGListDisplayDelegate</a>
</li>
<li class="nav-group-task">
<a href="Protocols/IGListScrollDelegate.html">IGListScrollDelegate</a>
</li>
<li class="nav-group-task">
<a href="Protocols/IGListSingleSectionControllerDelegate.html">IGListSingleSectionControllerDelegate</a>
</li>
<li class="nav-group-task">
<a href="Protocols/IGListSupplementaryViewSource.html">IGListSupplementaryViewSource</a>
</li>
<li class="nav-group-task">
<a href="Protocols/IGListTransitionDelegate.html">IGListTransitionDelegate</a>
</li>
<li class="nav-group-task">
<a href="Protocols/IGListUpdatingDelegate.html">IGListUpdatingDelegate</a>
</li>
<li class="nav-group-task">
<a href="Protocols/IGListWorkingRangeDelegate.html">IGListWorkingRangeDelegate</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a href="Type%20Definitions.html">Type Definitions</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a href="Type%20Definitions/IGListAdaptiveCoalescingExperimentConfig.html">IGListAdaptiveCoalescingExperimentConfig</a>
</li>
<li class="nav-group-task">
<a href="Type%20Definitions/IGListAdaptiveDiffingExperimentConfig.html">IGListAdaptiveDiffingExperimentConfig</a>
</li>
<li class="nav-group-task">
<a href="Type%20Definitions/IGListCollectionScrollingTraits.html">IGListCollectionScrollingTraits</a>
</li>
<li class="nav-group-task">
<a href="Type%20Definitions.html#/c:IGListUpdatingDelegate.h@T@IGListCollectionViewBlock">IGListCollectionViewBlock</a>
</li>
<li class="nav-group-task">
<a href="Type%20Definitions.html#/c:IGListUpdatingDelegate.h@T@IGListDataSourceChangeBlock">IGListDataSourceChangeBlock</a>
</li>
<li class="nav-group-task">
<a href="Type%20Definitions.html#/c:IGListUpdatingDelegate.h@T@IGListItemUpdateBlock">IGListItemUpdateBlock</a>
</li>
<li class="nav-group-task">
<a href="Type%20Definitions.html#/c:IGListUpdatingDelegate.h@T@IGListObjectTransitionBlock">IGListObjectTransitionBlock</a>
</li>
<li class="nav-group-task">
<a href="Type%20Definitions.html#/c:IGListUpdatingDelegate.h@T@IGListReloadUpdateBlock">IGListReloadUpdateBlock</a>
</li>
<li class="nav-group-task">
<a href="Type%20Definitions.html#/c:IGListSingleSectionController.h@T@IGListSingleSectionCellConfigureBlock">IGListSingleSectionCellConfigureBlock</a>
</li>
<li class="nav-group-task">
<a href="Type%20Definitions.html#/c:IGListSingleSectionController.h@T@IGListSingleSectionCellSizeBlock">IGListSingleSectionCellSizeBlock</a>
</li>
<li class="nav-group-task">
<a href="Type%20Definitions.html#/c:IGListUpdatingDelegate.h@T@IGListToObjectBlock">IGListToObjectBlock</a>
</li>
<li class="nav-group-task">
<a href="Type%20Definitions.html#/c:IGListUpdatingDelegate.h@T@IGListTransitionDataApplyBlock">IGListTransitionDataApplyBlock</a>
</li>
<li class="nav-group-task">
<a href="Type%20Definitions.html#/c:IGListUpdatingDelegate.h@T@IGListTransitionDataBlock">IGListTransitionDataBlock</a>
</li>
<li class="nav-group-task">
<a href="Type%20Definitions.html#/c:IGListAdapter.h@T@IGListUpdaterCompletion">IGListUpdaterCompletion</a>
</li>
<li class="nav-group-task">
<a href="Type%20Definitions.html#/c:IGListUpdatingDelegate.h@T@IGListUpdatingCompletion">IGListUpdatingCompletion</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a href="Functions.html">Functions</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a href="Functions.html#/c:@F@IGListDiff">IGListDiff</a>
</li>
<li class="nav-group-task">
<a href="Functions.html#/c:@F@IGListDiffPaths">IGListDiffPaths</a>
</li>
<li class="nav-group-task">
<a href="Functions.html#/c:IGListExperiments.h@F@IGListExperimentEnabled">IGListExperimentEnabled</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a href="Structs.html">Structures</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a href="Structs/IGListAdaptiveCoalescingExperimentConfig.html">IGListAdaptiveCoalescingExperimentConfig</a>
</li>
<li class="nav-group-task">
<a href="Structs/IGListAdaptiveDiffingExperimentConfig.html">IGListAdaptiveDiffingExperimentConfig</a>
</li>
<li class="nav-group-task">
<a href="Structs/IGListCollectionScrollingTraits.html">IGListCollectionScrollingTraits</a>
</li>
</ul>
</li>
</ul>
</nav>
<article class="main-content">
<section>
<section class="section">
<h1 id='getting-started' class='heading'>Getting Started</h1>
<p>This guide provides a brief overview for how to get started using <code>IGListKit</code>.</p>
<h2 id='creating-your-first-list' class='heading'>Creating your first list</h2>
<p>After installing <code>IGListKit</code>, creating a new list is easy.</p>
<h3 id='creating-a-section-controller' class='heading'>Creating a section controller</h3>
<p>Creating a new section controller is simple. Subclass <code><a href="Classes/IGListSectionController.html">IGListSectionController</a></code> and override at least <code>cellForItemAtIndex:</code> and <code>sizeForItemAtIndex:</code>.</p>
<p>Take a look at <a href="https://raw.githubusercontent.com/Instagram/IGListKit/main/Examples/Examples-iOS/IGListKitExamples/SectionControllers/LabelSectionController.swift">LabelSectionController</a> for an example section controller that handles a <code>String</code> and configures a single cell with a <code>UILabel</code>.</p>
<pre class="highlight swift"><code><span class="kd">class</span> <span class="kt">LabelSectionController</span><span class="p">:</span> <span class="kt">ListSectionController</span> <span class="p">{</span>
<span class="k">override</span> <span class="kd">func</span> <span class="nf">sizeForItem</span><span class="p">(</span><span class="n">at</span> <span class="nv">index</span><span class="p">:</span> <span class="kt">Int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">CGSize</span> <span class="p">{</span>
<span class="k">return</span> <span class="kt">CGSize</span><span class="p">(</span><span class="nv">width</span><span class="p">:</span> <span class="n">collectionContext</span><span class="o">!.</span><span class="n">containerSize</span><span class="o">.</span><span class="n">width</span><span class="p">,</span> <span class="nv">height</span><span class="p">:</span> <span class="mi">55</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">override</span> <span class="kd">func</span> <span class="nf">cellForItem</span><span class="p">(</span><span class="n">at</span> <span class="nv">index</span><span class="p">:</span> <span class="kt">Int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">UICollectionViewCell</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">collectionContext</span><span class="o">!.</span><span class="nf">dequeueReusableCell</span><span class="p">(</span><span class="nv">of</span><span class="p">:</span> <span class="kt">MyCell</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">for</span><span class="p">:</span> <span class="k">self</span><span class="p">,</span> <span class="nv">at</span><span class="p">:</span> <span class="n">index</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre>
<h3 id='creating-the-ui' class='heading'>Creating the UI</h3>
<p>After creating at least one section controller, you must create a <code>UICollectionView</code> and <code><a href="Classes/IGListAdapter.html">IGListAdapter</a></code>.</p>
<pre class="highlight swift"><code><span class="k">let</span> <span class="nv">layout</span> <span class="o">=</span> <span class="kt">UICollectionViewFlowLayout</span><span class="p">()</span>
<span class="k">let</span> <span class="nv">collectionView</span> <span class="o">=</span> <span class="kt">UICollectionView</span><span class="p">(</span><span class="nv">frame</span><span class="p">:</span> <span class="o">.</span><span class="n">zero</span><span class="p">,</span> <span class="nv">collectionViewLayout</span><span class="p">:</span> <span class="n">layout</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">updater</span> <span class="o">=</span> <span class="kt">ListAdapterUpdater</span><span class="p">()</span>
<span class="k">let</span> <span class="nv">adapter</span> <span class="o">=</span> <span class="kt">ListAdapter</span><span class="p">(</span><span class="nv">updater</span><span class="p">:</span> <span class="n">updater</span><span class="p">,</span> <span class="nv">viewController</span><span class="p">:</span> <span class="k">self</span><span class="p">)</span>
<span class="n">adapter</span><span class="o">.</span><span class="n">collectionView</span> <span class="o">=</span> <span class="n">collectionView</span>
</code></pre>
<blockquote>
<p><strong>Note:</strong> This example is done within a <code>UIViewController</code> and uses both a stock <code>UICollectionViewFlowLayout</code> and <code><a href="Classes/IGListAdapterUpdater.html">IGListAdapterUpdater</a></code>. You can use your own layout and updater if you need advanced features!</p>
</blockquote>
<h3 id='connecting-the-data-source' class='heading'>Connecting the data source</h3>
<p>The last step is the <code><a href="Classes/IGListAdapter.html">IGListAdapter</a></code>&lsquo;s data source and returning some data.</p>
<pre class="highlight swift"><code><span class="kd">func</span> <span class="nf">objects</span><span class="p">(</span><span class="k">for</span> <span class="nv">listAdapter</span><span class="p">:</span> <span class="kt">ListAdapter</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="kt">ListDiffable</span><span class="p">]</span> <span class="p">{</span>
<span class="c1">// this can be anything!</span>
<span class="k">return</span> <span class="p">[</span> <span class="s">"Foo"</span><span class="p">,</span> <span class="s">"Bar"</span><span class="p">,</span> <span class="mi">42</span><span class="p">,</span> <span class="s">"Biz"</span> <span class="p">]</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">listAdapter</span><span class="p">(</span><span class="n">_</span> <span class="nv">listAdapter</span><span class="p">:</span> <span class="kt">ListAdapter</span><span class="p">,</span> <span class="n">sectionControllerFor</span> <span class="nv">object</span><span class="p">:</span> <span class="kt">Any</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">ListSectionController</span> <span class="p">{</span>
<span class="k">if</span> <span class="n">object</span> <span class="k">is</span> <span class="kt">String</span> <span class="p">{</span>
<span class="k">return</span> <span class="kt">LabelSectionController</span><span class="p">()</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="k">return</span> <span class="kt">NumberSectionController</span><span class="p">()</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">emptyView</span><span class="p">(</span><span class="k">for</span> <span class="nv">listAdapter</span><span class="p">:</span> <span class="kt">ListAdapter</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">UIView</span><span class="p">?</span> <span class="p">{</span>
<span class="k">return</span> <span class="kc">nil</span>
<span class="p">}</span>
</code></pre>
<p>After you have created the data source you need to connect it to the <code><a href="Classes/IGListAdapter.html">IGListAdapter</a></code> by setting its <code>dataSource</code> property:</p>
<pre class="highlight swift"><code><span class="n">adapter</span><span class="o">.</span><span class="n">dataSource</span> <span class="o">=</span> <span class="k">self</span>
</code></pre>
<p>You can return an array of <em>any</em> type of data, as long as it conforms to <code><a href="Protocols/IGListDiffable.html">IGListDiffable</a></code>.</p>
<h3 id='immutability' class='heading'>Immutability</h3>
<p>The data should be immutable. If you return mutable objects that you will be editing later, <code>IGListKit</code> will not be able to diff the models accurately. This is because the instances have already been changed. Thus, the updates to the objects would be lost. Instead, always return a newly instantiated, immutable object and implement <code><a href="Protocols/IGListDiffable.html">IGListDiffable</a></code>.</p>
<h2 id='diffing' class='heading'>Diffing</h2>
<p><code>IGListKit</code> uses an algorithm adapted from a paper titled <a href="http://dl.acm.org/citation.cfm?id=359467&dl=ACM&coll=DL">A technique for isolating differences between files</a> by Paul Heckel. This algorithm uses a technique known as the <em>longest common subsequence</em> to find a minimal diff between collections in linear time <code>O(n)</code>. It finds all <strong>inserts</strong>, <strong>deletes</strong>, <strong>updates</strong>, and <strong>moves</strong> between arrays of data.</p>
<p>To add custom, diffable models, you need to conform to the <code><a href="Protocols/IGListDiffable.html">IGListDiffable</a></code> protocol and implement <code>diffIdentifier()</code> and <code>isEqual(toDiffableObject:)</code>.</p>
<blockquote>
<p><strong>Note:</strong> an object&rsquo;s <code>diffIdentifier()</code> should never change. If an object mutates it&rsquo;s <code>diffIdentifer()</code> the behavior of IGListKit is undefined (and almost assuredly undesirable).</p>
</blockquote>
<p>For an example, consider the following model:</p>
<pre class="highlight swift"><code><span class="kd">class</span> <span class="kt">User</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">primaryKey</span><span class="p">:</span> <span class="kt">Int</span>
<span class="k">let</span> <span class="nv">name</span><span class="p">:</span> <span class="kt">String</span>
<span class="c1">// implementation, etc</span>
<span class="p">}</span>
</code></pre>
<p>The user&rsquo;s <code>primaryKey</code> uniquely identifies user data, and the <code>name</code> is just the value for that user.</p>
<p>Let&rsquo;s say a server returns a <code>User</code> object that looks like this:</p>
<pre class="highlight swift"><code><span class="k">let</span> <span class="nv">shayne</span> <span class="o">=</span> <span class="kt">User</span><span class="p">(</span><span class="nv">primaryKey</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="nv">name</span><span class="p">:</span> <span class="s">"Shayne"</span><span class="p">)</span>
</code></pre>
<p>But sometime after the client receives <code>shayne</code>, someone changes their name:</p>
<pre class="highlight swift"><code><span class="k">let</span> <span class="nv">ann</span> <span class="o">=</span> <span class="kt">User</span><span class="p">(</span><span class="nv">primaryKey</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="nv">name</span><span class="p">:</span> <span class="s">"Ann"</span><span class="p">)</span>
</code></pre>
<p>Both <code>shayne</code> and <code>ann</code> represent the same <em>unique</em> data because they share the same <code>primaryKey</code>, but they are not <em>equal</em> because their names are different.</p>
<p>To represent this in <code>IGListKit</code>&rsquo;s diffing, add and implement the <code><a href="Protocols/IGListDiffable.html">IGListDiffable</a></code> protocol:</p>
<pre class="highlight swift"><code><span class="kd">extension</span> <span class="kt">User</span><span class="p">:</span> <span class="kt">ListDiffable</span> <span class="p">{</span>
<span class="kd">func</span> <span class="nf">diffIdentifier</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">NSObjectProtocol</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">primaryKey</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">isEqual</span><span class="p">(</span><span class="n">toDiffableObject</span> <span class="nv">object</span><span class="p">:</span> <span class="kt">Any</span><span class="p">?)</span> <span class="o">-&gt;</span> <span class="kt">Bool</span> <span class="p">{</span>
<span class="k">if</span> <span class="k">let</span> <span class="nv">object</span> <span class="o">=</span> <span class="n">object</span> <span class="k">as?</span> <span class="kt">User</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">name</span> <span class="o">==</span> <span class="n">object</span><span class="o">.</span><span class="n">name</span>
<span class="p">}</span>
<span class="k">return</span> <span class="kc">false</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre>
<p>The algorithm will skip updating two <code>User</code> objects that have the same <code>primaryKey</code> and <code>name</code>, even if they are different instances! You now avoid unnecessary UI updates in the collection view even when providing new instances.</p>
<blockquote>
<p><strong>Note:</strong> Remember that <code>isEqual(toDiffableObject:)</code> should return <code>false</code> when you want to reload the cells in the corresponding section controller.</p>
</blockquote>
<h3 id='diffing-outside-of-iglistkit' class='heading'>Diffing outside of IGListKit</h3>
<p>If you want to use the diffing algorithm outside of <code><a href="Classes/IGListAdapter.html">IGListAdapter</a></code> and <code>UICollectionView</code>, you can! The diffing algorithm was built with the flexibility to be used with any models that conform to <code><a href="Protocols/IGListDiffable.html">IGListDiffable</a></code>.</p>
<pre class="highlight swift"><code><span class="k">let</span> <span class="nv">result</span> <span class="o">=</span> <span class="kt">ListDiff</span><span class="p">(</span><span class="nv">oldArray</span><span class="p">:</span> <span class="n">oldUsers</span><span class="p">,</span> <span class="nv">newArray</span><span class="p">:</span> <span class="n">newUsers</span><span class="p">,</span> <span class="o">.</span><span class="n">equality</span><span class="p">)</span>
</code></pre>
<p>With this you have all of the deletes, reloads, moves, and inserts! There&rsquo;s even a function to generate <code>NSIndexPath</code> results.</p>
<h2 id='advanced-features' class='heading'>Advanced Features</h2>
<h3 id='working-range' class='heading'>Working Range</h3>
<p>A <em>working range</em> is a range of section controllers who aren&rsquo;t yet visible, but are near the screen. Section controllers are notified of their entrance and exit to this range. This concept lets your section controllers <strong>prepare content</strong> before they come on screen (e.g. download images).</p>
<p>The <code><a href="Classes/IGListAdapter.html">IGListAdapter</a></code> must be initialized with a range value in order to work. This value is a multiple of the visible height or width, depending on the scroll-direction.</p>
<pre class="highlight swift"><code><span class="k">let</span> <span class="nv">adapter</span> <span class="o">=</span> <span class="kt">ListAdapter</span><span class="p">(</span><span class="nv">updater</span><span class="p">:</span> <span class="kt">ListAdapterUpdater</span><span class="p">(),</span>
<span class="nv">viewController</span><span class="p">:</span> <span class="k">self</span><span class="p">,</span>
<span class="nv">workingRangeSize</span><span class="p">:</span> <span class="mi">1</span><span class="p">)</span> <span class="c1">// 1 before/after visible objects</span>
</code></pre>
<p><img src="https://raw.githubusercontent.com/Instagram/IGListKit/main/Resources/workingrange.png" alt="working-range"></p>
<p>You can set the weak <code>workingRangeDelegate</code> on a section controller to receive events.</p>
<h3 id='supplementary-views' class='heading'>Supplementary Views</h3>
<p>Adding supplementary views to section controllers is as simple as setting the (weak) <code>supplementaryViewSource</code> and implementing the <code><a href="Protocols/IGListSupplementaryViewSource.html">IGListSupplementaryViewSource</a></code> protocol. This protocol works nearly the same as returning and configuring cells.</p>
<h3 id='display-delegate' class='heading'>Display Delegate</h3>
<p>Section controllers can set the weak <code>displayDelegate</code> delegate to an object, including <code>self</code>, to receive display events about a section controller and individual cells.</p>
<h3 id='custom-updaters' class='heading'>Custom Updaters</h3>
<p>The default <code><a href="Classes/IGListAdapterUpdater.html">IGListAdapterUpdater</a></code> should handle any <code>UICollectionView</code> update that you need. However, if you find the functionality lacking, or want to perform updates in a very specific way, you can create an object that conforms to the <code><a href="Protocols/IGListUpdatingDelegate.html">IGListUpdatingDelegate</a></code> protocol and initialize a new <code><a href="Classes/IGListAdapter.html">IGListAdapter</a></code> with it.</p>
<p>Check out the updater <code><a href="Classes.html#/c:objc(cs)IGListReloadDataUpdater">IGListReloadDataUpdater</a></code> (used in unit tests) for an example.</p>
</section>
</section>
<section id="footer">
<p>&copy; 2026 <a class="link" href="https://twitter.com/MetaOpenSource" target="_blank" rel="external noopener">Instagram</a>. All rights reserved. (Last updated: 2026-02-15)</p>
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external noopener">jazzy ♪♫ v0.15.4</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external noopener">Realm</a> project.</p>
</section>
</article>
</div>
</body>
</html>