mirror of
https://github.com/Instagram/IGListKit
synced 2026-05-02 19:07:35 +00:00
Summary: Added migration guide for `IGListDiffable` changes. Closes #221 Closes https://github.com/Instagram/IGListKit/pull/274 Differential Revision: D4265446 Pulled By: rnystrom fbshipit-source-id: b98a975a9ef65bca0d46a1011e76834ecf08c681
308 lines
19 KiB
HTML
308 lines
19 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<title>IGListDiffable and Equality 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>
|
|
|
|
</head>
|
|
<body>
|
|
<a title="IGListDiffable and Equality Reference"></a>
|
|
<header>
|
|
<div class="content-wrapper">
|
|
<p><a href="index.html">IGListKit Docs</a> (100% documented)</p>
|
|
<p class="header-right"><a href="https://github.com/Instagram/IGListKit"><img src="img/gh.png"/>View on GitHub</a></p>
|
|
</div>
|
|
</header>
|
|
<div class="content-wrapper">
|
|
<p id="breadcrumbs">
|
|
<a href="index.html">IGListKit Reference</a>
|
|
<img id="carat" src="img/carat.png" />
|
|
IGListDiffable and Equality 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="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="migration.html">Migration</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.html#/c:objc(cy)NSNumber@IGListDiffable">NSNumber(IGListDiffable)</a>
|
|
</li>
|
|
<li class="nav-group-task">
|
|
<a href="Categories.html#/c:objc(cy)NSString@IGListDiffable">NSString(IGListDiffable)</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/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.html#/c:objc(cs)IGListCollectionView">IGListCollectionView</a>
|
|
</li>
|
|
<li class="nav-group-task">
|
|
<a href="Classes/IGListGridCollectionViewLayout.html">IGListGridCollectionViewLayout</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/IGListStackedSectionController.html">IGListStackedSectionController</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">Enums</a>
|
|
<ul class="nav-group-tasks">
|
|
<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/IGListAdapterUpdaterDelegate.html">IGListAdapterUpdaterDelegate</a>
|
|
</li>
|
|
<li class="nav-group-task">
|
|
<a href="Protocols/IGListCollectionContext.html">IGListCollectionContext</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/IGListSectionType.html">IGListSectionType</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/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 Definitions.html">Type Definitions</a>
|
|
<ul class="nav-group-tasks">
|
|
<li class="nav-group-task">
|
|
<a href="Type Definitions.html#/c:IGListUpdatingDelegate.h@T@IGListItemUpdateBlock">IGListItemUpdateBlock</a>
|
|
</li>
|
|
<li class="nav-group-task">
|
|
<a href="Type Definitions.html#/c:IGListUpdatingDelegate.h@T@IGListObjectTransitionBlock">IGListObjectTransitionBlock</a>
|
|
</li>
|
|
<li class="nav-group-task">
|
|
<a href="Type Definitions.html#/c:IGListUpdatingDelegate.h@T@IGListReloadUpdateBlock">IGListReloadUpdateBlock</a>
|
|
</li>
|
|
<li class="nav-group-task">
|
|
<a href="Type Definitions.html#/c:IGListSingleSectionController.h@T@IGListSingleSectionCellConfigureBlock">IGListSingleSectionCellConfigureBlock</a>
|
|
</li>
|
|
<li class="nav-group-task">
|
|
<a href="Type Definitions.html#/c:IGListSingleSectionController.h@T@IGListSingleSectionCellSizeBlock">IGListSingleSectionCellSizeBlock</a>
|
|
</li>
|
|
<li class="nav-group-task">
|
|
<a href="Type Definitions.html#/c:IGListAdapter.h@T@IGListUpdaterCompletion">IGListUpdaterCompletion</a>
|
|
</li>
|
|
<li class="nav-group-task">
|
|
<a href="Type Definitions.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@IGListDiffExperiment">IGListDiffExperiment</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:@F@IGListDiffPathsExperiment">IGListDiffPathsExperiment</a>
|
|
</li>
|
|
<li class="nav-group-task">
|
|
<a href="Functions.html#/c:IGListExperiments.h@F@IGListExperimentEnabled">IGListExperimentEnabled</a>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
<article class="main-content">
|
|
<section>
|
|
<section class="section">
|
|
|
|
<a href='#iglistdiffable-and-equality' class='anchor' aria-hidden=true><span class="header-anchor"></span></a><h1 id='iglistdiffable-and-equality'>IGListDiffable and Equality</h1>
|
|
|
|
<p>This guide details how to write good <code>isEqual:</code> methods. </p>
|
|
<a href='#background' class='anchor' aria-hidden=true><span class="header-anchor"></span></a><h2 id='background'>Background</h2>
|
|
|
|
<p><code>IGListKit</code> requires that models implement the method <code>isEqualToDiffableObject:</code> which should perform the same type of check as <code>isEqual:</code>, but without impacting performance characteristics like in Objective-C containers such as <code>NSDictionary</code> and <code>NSSet</code>.</p>
|
|
<a href='#code-iglistdiffable-code-bare-minimum' class='anchor' aria-hidden=true><span class="header-anchor"></span></a><h2 id='code-iglistdiffable-code-bare-minimum'><code>IGListDiffable</code> bare minimum</h2>
|
|
|
|
<p>The quickest way to get started with diffable models is use the <em>object itself</em> as the identifier, and use the superclass’s <code>-[NSObject isEqual:]</code> implementation for equality:</p>
|
|
<pre class="highlight objective_c"><code><span class="k">-</span> <span class="p">(</span><span class="n">id</span><span class="o"><</span><span class="n">NSObject</span><span class="o">></span><span class="p">)</span><span class="n">diffIdentifier</span> <span class="p">{</span>
|
|
<span class="k">return</span> <span class="n">self</span><span class="p">;</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="o">-</span> <span class="p">(</span><span class="n">BOOL</span><span class="p">)</span><span class="n">isEqualToDiffableObject</span><span class="o">:</span><span class="p">(</span><span class="n">id</span><span class="o"><</span><span class="n">IGListDiffable</span><span class="o">></span><span class="p">)</span><span class="n">object</span> <span class="p">{</span>
|
|
<span class="k">return</span> <span class="p">[</span><span class="n">self</span> <span class="nf">isEqual</span><span class="p">:</span><span class="n">object</span><span class="p">];</span>
|
|
<span class="p">}</span>
|
|
</code></pre>
|
|
<a href='#writing-better-equality-methods' class='anchor' aria-hidden=true><span class="header-anchor"></span></a><h2 id='writing-better-equality-methods'>Writing better Equality methods</h2>
|
|
|
|
<p>Even though <code>IGListKit</code> uses the method <code>isEqualToDiffableObject:</code>, the concepts of writing a good equality check apply in general. Here are the basics to writing good <code>-isEqual:</code> and <code>-hash</code> functions. Note this is all Objective-C but applies to Swift also.</p>
|
|
|
|
<ul>
|
|
<li>If you override <code>-isEqual:</code> you <strong>must</strong> override <code>-hash</code>. Check out this <a href="https://www.mikeash.com/pyblog/friday-qa-2010-06-18-implementing-equality-and-hashing.html">article by Mike Ash</a> for details.</li>
|
|
<li>Always compare the pointer first. This saves a lot of wasteful <code>objc_msgSend(...)</code> calls and value comparisons if checking the same instance.</li>
|
|
<li>When comparing object values, always check for <code>nil</code> before <code>-isEqual:</code>. For example, <code>[nil isEqual:nil]</code> unintuitively returns <code>NO</code>. Instead, do <code>left == right || [left isEqual:right]</code>.</li>
|
|
<li>Always compare the <strong>cheapest values first</strong>. For example, doing <code>[self.array isEqual:other.array] && self.intVal == other.array</code> is extremely wasteful if the <code>intVal</code> values are different. Use lazy evaluation!</li>
|
|
</ul>
|
|
|
|
<p>As an example, if I had a <code>User</code> model with the following interface:</p>
|
|
<pre class="highlight objective_c"><code><span class="k">@interface</span> <span class="nc">User</span> <span class="p">:</span> <span class="nc">NSObject</span>
|
|
|
|
<span class="k">@property</span> <span class="n">NSInteger</span> <span class="n">identifier</span><span class="p">;</span>
|
|
<span class="k">@property</span> <span class="n">NSString</span> <span class="o">*</span><span class="n">name</span><span class="p">;</span>
|
|
<span class="k">@property</span> <span class="n">NSArray</span> <span class="o">*</span><span class="n">posts</span><span class="p">;</span>
|
|
|
|
<span class="k">@end</span>
|
|
</code></pre>
|
|
|
|
<p>You would implement its equality methods like so:</p>
|
|
<pre class="highlight objective_c"><code><span class="k">@implementation</span> <span class="nc">User</span>
|
|
|
|
<span class="k">-</span> <span class="p">(</span><span class="n">NSUInteger</span><span class="p">)</span><span class="n">hash</span> <span class="p">{</span>
|
|
<span class="k">return</span> <span class="n">self</span><span class="p">.</span><span class="n">identifier</span><span class="p">;</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="o">-</span> <span class="p">(</span><span class="n">BOOL</span><span class="p">)</span><span class="n">isEqual</span><span class="o">:</span><span class="p">(</span><span class="n">id</span><span class="p">)</span><span class="n">object</span> <span class="p">{</span>
|
|
<span class="k">if</span> <span class="p">(</span><span class="n">self</span> <span class="o">==</span> <span class="n">object</span><span class="p">)</span> <span class="p">{</span>
|
|
<span class="k">return</span> <span class="nb">YES</span><span class="p">;</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="p">[</span><span class="n">object</span> <span class="nf">isKindOfClass</span><span class="p">:[</span><span class="n">User</span> <span class="nf">class</span><span class="p">]])</span> <span class="p">{</span>
|
|
<span class="k">return</span> <span class="nb">NO</span><span class="p">;</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="n">User</span> <span class="o">*</span><span class="n">right</span> <span class="o">=</span> <span class="n">object</span><span class="p">;</span>
|
|
<span class="k">return</span> <span class="n">self</span><span class="p">.</span><span class="n">identifier</span> <span class="o">==</span> <span class="n">right</span><span class="p">.</span><span class="n">identifier</span>
|
|
<span class="o">&&</span> <span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">name</span> <span class="o">==</span> <span class="n">right</span><span class="p">.</span><span class="n">name</span> <span class="o">||</span> <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">name</span> <span class="nf">isEqual</span><span class="p">:</span><span class="n">right</span><span class="p">.</span><span class="n">name</span><span class="p">])</span>
|
|
<span class="o">&&</span> <span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">posts</span> <span class="o">==</span> <span class="n">right</span><span class="p">.</span><span class="n">posts</span> <span class="o">||</span> <span class="p">[</span><span class="n">self</span><span class="p">.</span><span class="n">posts</span> <span class="nf">isEqualToArray</span><span class="p">:</span><span class="n">right</span><span class="p">.</span><span class="n">posts</span><span class="p">]);</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="k">@end</span>
|
|
</code></pre>
|
|
<a href='#using-both-code-iglistdiffable-code-and-code-isequal-code' class='anchor' aria-hidden=true><span class="header-anchor"></span></a><h2 id='using-both-code-iglistdiffable-code-and-code-isequal-code'>Using both <code>IGListDiffable</code> and <code>-isEqual:</code></h2>
|
|
|
|
<p>Making your objects work universally with Objective-C containers and <code>IGListKit</code> is easy once you’ve implemented <code>isEqual:</code> and <code>-hash</code>.</p>
|
|
<pre class="highlight objective_c"><code><span class="k">@interface</span> <span class="nc">User</span> <span class="o"><</span><span class="n">IGListDiffable</span><span class="o">></span>
|
|
|
|
<span class="c1">// properties...
|
|
</span>
|
|
<span class="k">@end</span>
|
|
|
|
<span class="k">@implementation</span> <span class="nc">User</span>
|
|
|
|
<span class="k">-</span> <span class="p">(</span><span class="n">id</span><span class="o"><</span><span class="n">NSObject</span><span class="o">></span><span class="p">)</span><span class="n">diffIdentifier</span> <span class="p">{</span>
|
|
<span class="k">return</span> <span class="err">@</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">identifier</span><span class="p">);</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="o">-</span> <span class="p">(</span><span class="n">BOOL</span><span class="p">)</span><span class="n">isEqualToDiffableObject</span><span class="o">:</span><span class="p">(</span><span class="n">id</span><span class="o"><</span><span class="n">IGListDiffable</span><span class="o">></span><span class="p">)</span><span class="n">object</span> <span class="p">{</span>
|
|
<span class="k">return</span> <span class="p">[</span><span class="n">self</span> <span class="nf">isEqual</span><span class="p">:</span><span class="n">object</span><span class="p">];</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="k">@end</span>
|
|
</code></pre>
|
|
|
|
</section>
|
|
</section>
|
|
<section id="footer">
|
|
<p>© 2016 <a class="link" href="https://twitter.com/fbOpenSource" target="_blank" rel="external">Instagram</a>. All rights reserved. (Last updated: 2016-12-02)</p>
|
|
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.7.2</a>, a <a class="link" href="http://realm.io" target="_blank" rel="external">Realm</a> project.</p>
|
|
</section>
|
|
</article>
|
|
</div>
|
|
</body>
|
|
</div>
|
|
</html>
|