<p>You can follow along and build the example in this guide. First, you must download <ahref="https://github.com/rnystrom/IGListKit-Binding-Guide">this starter project</a>. Open <strong>ModelingAndBinding-Starter/ModelingAndBinding.xcworkspace</strong> since the base project is setup with CocoaPods with <code>IGListKit</code> already added as a dependency.</p>
<p>Take a look at the following Instagram-inspired list element design:</p>
<p>You can already start mentally modelling your data:</p>
<ul>
<li>The top cell has a <strong>username</strong> and <strong>timestamp</strong> label</li>
<li>The image cell will need some sort of image <code>URL</code></li>
<li>An action cell with <strong>like count</strong>. There will also need to be some sort of action handling when someone taps the heart</li>
<li>Then there are a <em>dynamic</em> number of comment cells that contain a <strong>username</strong> and <strong>comment</strong></li>
</ul>
<p>Remember that <code>IGListKit</code> functions on <strong>one model per section controller</strong>. All of the cells in this design correlate to one top-level <q>post</q> object delivered by a server. You want to create a <code>Post</code> model that contains all of the information that the cells require.</p>
<blockquote>
<p>A common mistake is to create a single model and section controller for a single cell. In this example, that will create a <strong>very confusing</strong> architecture since the top-level objects will contain a mix and match of user, image, action, and comment models.</p>
<li>It’s best practice to always declare your values as <code>let</code> so they cannot be mutated again. The compiler will complain about the <code>Comment</code> model, ignore that for now.</li>
<divclass="aside aside-since">
<pclass="aside-title">Since</p>
Since <code>IGListKit</code> is compatible with Objective-C, your models must be <code>class</code>es which means writing initializers. It’s only a little copy & paste!
</div>
<p>Now add a <code>ListDiffable</code> implementation inside of <code>Post</code>:</p>
<li>Derive a <strong>unique identifier</strong> for each post. Since a single post should never have the same <code>username</code> and <code>timestamp</code> combo, we can start with that.</li>
<li>A <strong>core requirement</strong> to using <code>ListBindingSectionController</code> is that if two models have the same <code>diffIdentifier</code>, they <strong>must be equal</strong> so that the section controller can then compare view models.</li>
A note on the `isEqual(toDiffableObject:)` implementation: Whatever you use to derive the `diffIdentifier` can be omitted from any equality checks, since by definition the objects have already matched on their identifiers.
In this case, the `username` and `text` **must be equal** by the time two objects are checked for equality.
</p></details>
<p>Using the <code>Comment</code> array on a <code>Post</code> should make some sense: there are a dynamic number of comments on each post. For each comment, you want to display a cell.</p>
<p>What might be a little bit of a new concept, though, is that you need to create models for the <code>UserCell</code>, <code>ImageCell</code>, <em>and</em><code>ActionCell</code> as well when working with <code>ListBindingSectionController</code>.</p>
<blockquote>
<p>A binding section controller is almost like a mini-<code>IGListKit</code>. It takes an array of view models and turns them into configured cells. Get into the habit of creating a new model for each cell type within an <code>ListBindingSectionController</code> instance.</p>
</blockquote>
<p>With that in mind, let’s start with the model for the <code>UserCell</code>:</p>
<p>Create a new Swift file called <strong>UserViewModel.swift</strong>:</p>
Since there will only be <strong>one <code>UserViewModel</code> per <code>Post</code></strong>, you can hardcode an identifier. This will enforce only a single model & cell being used.
</div>
<li>It’s important to write a good equality method for these view models. Anytime something changes, forcing the models to not be equal, the cell will be refreshed.</li>
<p>Try to make view models for the <strong>image</strong> and <strong>action</strong> cell. Remember there is only a single cell per <code>Post</code>, so you can use <code>UserViewModel</code> as a starting point for how the models should look.</p>
> You could try getting away with using generics since these models look so similar, but we’ve found that using **simple** models makes long-term maintenance more manageable.
<p>You now have the following view models, which can all be derived from each <code>Post</code>:</p>
<ul>
<li><code>UserViewModel</code></li>
<li><code>ImageViewModel</code></li>
<li><code>ActionViewModel</code></li>
<li><code>Comment</code></li>
</ul>
<p>Let’s start using these models to power cells using <code>ListBindingSectionController</code>. This controller takes a top-level model (<code>Post</code>), asks its data source for an array of diffable view models (our view models above), then binds those view models to cells (provided in the starter project).</p>
<p>Notice that you are subclassing <code>ListBindingSectionController<Post></code>. This declares your section controller as receiving a <code>Post</code> model. That way you don’t have to do any special casting of your model.</p>
<p>There are 3 methods that are required to satisfy the data source protocol:</p>
<ul>
<li>Return an array of view models given the top-level model (<code>Post</code>)</li>
<li>Return a size for a given view model</li>
<li>Return a cell for a given view model</li>
</ul>
<p>First take care of the <code>Post</code>-to-view-models transformation:</p>
<li>The <code>object</code> property <strong>must</strong> be optional because it will not exist upon section controller initialization. However, it should never be nil at this point, nor should the <code>object: Any</code> parameter be anything but the section controller type. This is a limitation of Objective-C generics and protocols, so doing a <code>fatalError()</code> here is appropriate.</li>
<li>Create your array of view models by <em>decomposing</em> the <code>Post</code> model into smaller models.</li>
<li>You can even append dynamic models that are delivered from the server.</li>
</ol>
<p>Next add the required API to return a size for each view model:</p>
<li>Just like the <code>object</code> property, the <code>collectionContext</code> should never be <code>nil</code>, but it’s a weakly referenced object so must be declared as optional. Again, use <code>fatalError()</code> to catch any critical failures.</li>
<li>Swift makes checking for types so easy! Just <code>switch</code> on the type and assign a height. In Objective-C you should use <code>isKindOfClass:</code>.</li>
<li>Both the <code>UserViewModel</code> and <code>ActionViewModel</code> share the same height of <code>55</code>pts according to the design.</li>
</ol>
<p>Lastly, implement the API that returns a cell for each view model. This should look similar to the size API above. Give it a try yourself.</p>
<blockquote>
<p>Remember that the cells are defined in <strong>Main.storyboard</strong>. You can click on each cell to view their identifiers.</p>
Remember to handle `UserViewModel` and `ActionViewModel` separately!
</p></details>
<h2id='binding-models-to-cells'class='heading'>Binding Models to Cells</h2>
<p>Now you have <code>PostSectionController</code> setup to create view models, sizes, and cells. The last piece to using <code>ListBindingSectionController</code> is having your cells to receive its assigned view model and configure itself. </p>
<p>This is done by making your cells conform to <code>ListBindable</code>. With that, <code>ListBindingSectionController</code> will <strong>automatically</strong> bind view models to each cell!</p>
<p>Open <strong>ImageCell.swift</strong> and change the implementation to look like the following:</p>
<li>Make sure to import <code>IGListKit</code>!</li>
<li>Have the cell conform to <code>ListBindable</code></li>
<li>Guard against the view model type. This will always be what <code>PostSectionController</code> pairs the cell with in <code>cellForViewModel:</code>, but guard to be safe.</li>
<li>Use the <ahref="https://github.com/rs/SDWebImage">SDWebImage</a> library to set the image URL.</li>
</ol>
<p>Now do exactly the same thing for each of the other cells:</p>
<h2id='displaying-in-the-view-controller'class='heading'>Displaying in the View Controller</h2>
<p>The very last step is getting the <code>PostSectionController</code> displaying in the app’s list.</p>
<p>Go back to <strong>ViewController.swift</strong> and add the following to <code>viewDidLoad()</code>, <strong>before</strong> setting the <code>dataSource</code> or <code>collectionView</code>:</p>
<spanclass="kt">Comment</span><spanclass="p">(</span><spanclass="nv">username</span><spanclass="p">:</span><spanclass="s">"@ryan"</span><spanclass="p">,</span><spanclass="nv">text</span><spanclass="p">:</span><spanclass="s">"this is beautiful!"</span><spanclass="p">),</span>
<p>Normally you’d want to check the type of <code>object</code>, but since you’re only using <code>Post</code> at this point, it’s safe to simply return a new <code>PostSectionController</code>.</p>
</blockquote>
<p><strong>Build and run</strong> the sample app to see your post show up!</p>
<p><imgsrc="../Resources/modeling-working.png"alt="Working in the Simulator"></p>
<p>This design should respond to tapping the heart icon on the <code>ActionCell</code>. In order to do that, you need to handle taps on the <code>UIButton</code>, then forward the event to the <code>PostSectionController</code>:</p>
<p>Open <strong>ActionCell.swift</strong> and add the following protocol:</p>
<p>This will forward the button tap outside of the cell and to the delegate.</p>
<p>Open <strong>PostSectionController.swift</strong> and update the <code>cellForViewModel:</code> method. Add the following at the end of the method, just after the <code>guard</code> and right before you return the <code>cell</code>:</p>
<p>Every time someone taps the heart button, you need to add a new like to the <code>Post</code>. However, all of your models are declared with <code>let</code> because immutable models are a much safer design. But if everything is immutable, how do we mutate the like count?</p>
<p>The <code>PostSectionController</code> is the <em>perfect</em> place to handle and store mutations. Open <strong>PostSectionController.swift</strong> and add the following variable:</p>
<li>Mutate the <code>localLikes</code> variable using either the previous <code>localLikes</code> or starting with <code>object.likes</code>, whichever exists. Fallback to <code>0</code> which will never happen, just satisfying the compiler.</li>
<li>Call the <code>update(animated:,completion:)</code> API on <code>ListBindingSectionController</code> to refresh the cells on the screen.</li>
</ol>
<p>In order to actually send the mutations to the models, you need to start using <code>localLikes</code> with the <code>ActionViewModel</code> which is given to the <code>ActionCell</code>.</p>
<p>Still in <strong>PostSectionController.swift</strong>, find the <code>cellForViewModel:</code> API and change the <code>ActionViewModel</code> initialization to the following:</p>
<p>If you got stuck at all, or just want to play around with the example, you can find the finished project <ahref="https://github.com/rnystrom/IGListKit-Binding-Guide">here</a> in <strong>ModelingAndBinding/ModelingAndBinding.xcworkspace</strong>.</p>
<p><code>ListBindingSectionController</code> is one of the most powerful features that we’ve built for <code>IGListKit</code> because it further encourages you to design small, composable models, views, and controllers.</p>
<p>You can also use the section controller to handle any interactions, as well as deal with mutations, just like a controller should!</p>
<p>If you have suggestions for other topics you’d like to see, or want to offer a correction, please create a <ahref="https://github.com/Instagram/IGListKit/issues/new">new issue</a>!</p>
<p>Generated by <aclass="link"href="https://github.com/realm/jazzy"target="_blank"rel="external">jazzy ♪♫ v0.9.1</a>, a <aclass="link"href="http://realm.io"target="_blank"rel="external">Realm</a> project.</p>