# Technical Documentation: Instagram/IGListKit

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/Instagram/IGListKit)

### Overview (`README.md`)

<p align="center">
  <img src="https://raw.githubusercontent.com/Instagram/IGListKit/main/Resources/logo.png" width=450 />
</p>

<p align="center">
  <a href="https://github.com/Instagram/IGListKit/actions/workflows/CI.yml"><img src="https://img.shields.io/github/actions/workflow/status/Instagram/IGListKit/CI.yml" alt="Build Status"></a>
  <a href="https://coveralls.io/github/Instagram/IGListKit?branch=main"><img src="https://coveralls.io/repos/github/Instagram/IGListKit/badge.svg?branch=main" alt="Coverage Status" /></a>
  <a href="https://cocoapods.org/pods/IGListKit"><img src="https://img.shields.io/cocoapods/v/IGListKit.svg?style=flat" alt="Pods Version"></a>
  <a href="https://instagram.github.io/IGListKit/"><img src="https://img.shields.io/cocoapods/p/IGListKit.svg?style=flat" alt="Platforms"></a>
  <a href="https://github.com/Carthage/Carthage"><img src="https://img.shields.io/badge/Carthage-compatible-brightgreen.svg?style=flat" alt="Carthage Compatible"></a>
</p>

----------------

A data-driven `UICollectionView` framework for building fast and flexible lists.

|         | Main Features  |
----------|-----------------
&#128581; | Never call `performBatchUpdates(_:, completion:)` or `reloadData()` again
&#127968; | Better architecture with reusable cells and components
&#128288; | Create collections with multiple data types
&#128273; | Decoupled diffing algorithm
&#9989;   | Fully unit tested
&#128269; | Customize your diffing behavior for your models
&#128241; | Simply `UICollectionView` at its core
&#128640; | Extendable API
&#128038; | Written in Objective-C with full Swift interop support

`IGListKit` is built and maintained with &#10084;&#65039; by [Instagram engineering](https://engineering.instagram.com/).
We use the open source version `main` branch in the Instagram app.

## Multilingual translation

[Chinese README](README.zh.md)

## Requirements

- Swift 5.1+
- iOS 11.0+
- tvOS 11.0+
- macOS 10.13+ *(diffing algorithm components only)*
- Interoperability with Swift 3.0+

## Installation

### CocoaPods

The preferred installation method is with [CocoaPods](https://cocoapods.org). Add the following to your `Podfile`:

```ruby
pod 'IGListKit', '~> 5.2.0'
```

### Carthage

For [Carthage](https://github.com/Carthage/Carthage), add the following to your `Cartfile`:

```ogdl
github "Instagram/IGListKit" ~> 5.2.0
```

### Swift Package Manager

For [Swift Package Manager](https://swift.org/package-manager/):

```
To integrate using Xcode:

File -> Swift Packages -> Add Package Dependency

Enter package URL: https://github.com/Instagram/IGListKit, and select the latest release.
```

> For advanced usage, see our [Installation Guide](https://instagram.github.io/IGListKit/installation.html).

## Getting Started

Try out IGListKit by opening any of the sample apps available in the `Examples ` directory.

- Our [Getting Started guide](https://instagram.github.io/IGListKit/getting-started.html)
- Ray Wenderlich's [IGListKit Tutorial: Better UICollectionViews](https://www.raywenderlich.com/147162/iglistkit-tutorial-better-uicollectionviews)
- Our [example projects](https://github.com/Instagram/IGListKit/tree/main/Examples)
- Ryan Nystrom's [talk at try! Swift NYC](https://academy.realm.io/posts/tryswift-ryan-nystrom-refactoring-at-scale-lessons-learned-rewriting-instagram-feed/)(Note: this talk was for an earlier version. Some APIs have changed.)
- [Migrating an UITableView to IGListCollectionView](https://medium.com/cocoaacademymag/iglistkit-migrating-an-uitableview-to-iglistkitcollectionview-65a30cf9bac9), by Rodrigo Cavalcante
- [Keeping data fresh in Buffer for iOS with AsyncDisplayKit, IGListKit & Pusher](https://overflow.buffer.com/2017/04/10/keeping-data-fresh-buffer-ios-asyncdisplaykit-iglistkit-pusher/), Andy Yates, Buffer

## Documentation

You can find [the docs here](https://instagram.github.io/IGListKit). Documentation is generated with [jazzy](https://github.com/realm/jazzy) and hosted on [GitHub-Pages](https://pages.github.com).

To regenerate docs, run `./scripts/build_docs.sh` from the root directory in the repo.

## Vision

For the long-term goals and "vision" of `IGListKit`, please read our [Vision](https://github.com/Instagram/IGListKit/blob/main/Guides/VISION.md) doc.

## Contributing

Please see the [CONTRIBUTING](https://github.com/Instagram/IGListKit/blob/main/.github/CONTRIBUTING.md) file for how to help. At Instagram, we sync the open source version of `IGListKit` daily, so we're always testing the latest changes. But that requires all changes be thoroughly tested and follow our style guide.

We have a set of [starter tasks](https://github.com/Instagram/IGListKit/issues?q=is%3Aissue+is%3Aopen+label%3Astarter-task) that are great for beginners to jump in on and start contributing.

## License

`IGListKit` is [MIT-licensed](./LICENSE.md).

The files in the `/Examples/` directory are licensed under a separate license as specified in each file. Documentation is licensed [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/).

## Legal

Copyright © Meta Platforms, Inc &#x2022; <a href="https://opensource.fb.com/legal/terms">Terms of Use</a> &#x2022; <a href="https://opensource.fb.com/legal/privacy">Privacy Policy</a>

---

### Guides Best Practices And FAQ (`Guides/Best Practices and FAQ.md`)

# Best Practices and FAQs

This guide provides notes and details on best practices in using `IGListKit`, general tips, and answers to FAQs.

## Best Practices

- We recommend adding an assert to check [`-isKindOfClass:`](https://developer.apple.com/reference/objectivec/1418956-nsobject/1418511-iskindofclass) on the object you receive in [`-didUpdateToObject:`](https://github.com/Instagram/IGListKit/blob/main/Source/IGListSectionController.h#L63-L72) in your section controllers. 
This makes it easy to track down easily-overlooked mistakes in your [`IGListAdapaterDataSource`](https://instagram.github.io/IGListKit/Protocols/IGListAdapterDataSource.html#/c:objc(pl)IGListAdapterDataSource(im)listAdapter:sectionControllerForObject:) implementation. 
If this assert is ever hit, that means `IGListKit` has sent your section controller the incorrect type of object. 
This would only happen if your objects provide *non-unique* diff identifiers. 

```objective-c
// Objective-C
- (void)didUpdateToObject:(id)object {
    NSParameterAssert([object isKindOfClass:[MyModelClass class]]);
    _myModel = object;
}
```

```swift
// Swift
func didUpdate(to object: Any) {
    precondition(object is MyModelClass)
    myModel = object as! MyModelClass
}
```

- Make sure your [`-diffIdentifier`](https://instagram.github.io/IGListKit/Protocols/IGListDiffable.html#/c:objc(pl)IGListDiffable(im)diffIdentifier) implementation returns a **unique identifier** for each object.

- We highly recommend using single-item sections when possible. That is, each section controller manages a single model (which may have one or multiple cells). This gives you the greatest amount of flexibility, modularity, and re-use for your components.

## Frequently asked questions

#### I upgraded IGListKit and now everything is broken!

Check out our [migration guide](https://github.com/Instagram/IGListKit/blob/main/Guides/Migration.md) to make upgrading easier.

#### How do you implement separators between cells?

See discussion in [#329](https://github.com/Instagram/IGListKit/issues/329)

#### How do I fix the error `Could not build Objective-C module 'IGListKit'`?

See discussion in [#316](https://github.com/Instagram/IGListKit/issues/316)

#### The documentation and examples have `<X>` feature or changes, but I don't have it in my version. Why?

This feature is on the `main` branch only and hasn't been officially tagged and [released](https://github.com/Instagram/IGListKit/releases). If you need to, you can [install from the `main` branch](https://instagram.github.io/IGListKit/installation.html).

#### Does `IGListKit` work with...?

- Core Data ([Working with Core Data](https://instagram.github.io/IGListKit/working-with-core-data.html) Guide)
- AsyncDisplayKit ([AsyncDisplayKit/#2942](https://github.com/facebook/AsyncDisplayKit/pull/2942))
- ComponentKit ([ocrickard/IGListKit-ComponentKit](https://github.com/ocrickard/IGListKit-ComponentKit))
- RxSwift ([RxSwiftCommunity/RxIGListKit](https://github.com/RxSwiftCommunity/RxIGListKit))
- React Native
- Reactive Cocoa

Yes.

#### Does `IGListKit` work with `UITableView`?

No, but you can install the [diffing subspec via CocoaPods](https://instagram.github.io/IGListKit/installation.html).

#### What's the purpose of `IGListCollectionView`?

Historically, we used this subclass to gain compile-time safety to prevent disallowed methods from being called on `UICollectionView`, because `IGListKit` handles model and view updates. However, it has since been removed. See discussion at [#409](https://github.com/Instagram/IGListKit/issues/409).

#### How can I manage cell selection and deselection?

See discussion at [#184](https://github.com/Instagram/IGListKit/issues/184).

#### I have a *huge* data set and [`-performUpdatesAnimated: completion:`](https://instagram.github.io/IGListKit/Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)performUpdatesAnimated:completion:) is *super* slow. What do I do?

If you have multiple thousands of items and you cannot batch them in, you'll see performance issues with `-performUpdatesAnimated: completion:`. The real bottleneck behind the scenes here is `UICollectionView` attempting to insert so many cells at once. Instead, call [`-reloadDataWithCompletion:`](https://instagram.github.io/IGListKit/Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)reloadDataWithCompletion:) when you first load data. Behind the scenes, this method *does not* do any diffing and simply calls `-reloadData` on `UICollectionView`. For subsequent updates, you can then use `-performUpdatesAnimated: completion:`.

#### How do I use IGListKit and estimated cell sizes with Auto Layout?

This should work in theory, and we have an [example section controller](https://github.com/Instagram/IGListKit/blob/main/Examples/Examples-iOS/IGListKitExamples/SectionControllers/SelfSizingSectionController.swift), but the estimated-size API in `UICollectionViewFlowLayout` has changed dramatically over different iOS versions, making first-class support in IGListKit difficult. We don't use estimated cell sizes or Auto Layout in Instagram and cannot commit to fully supporting it.

See [#516](https://github.com/Instagram/IGListKit/issues/516) for a master list of all known issues. We very much welcome contribution to fixing this!

#### Is creating a "wrapper" model just for IGListKit ok?

Yes! We create models that act as a grab-bag for other models, specifically for use in section controllers. Things like:

```swift
class WeatherSectionModel {
  let location: Location
  let forecast: Forecast
  let conditions: Conditions
}
```

Just don't forget to make your models diffable using the data in the contained models:

```swift
extension WeatherSectionModel: ListDiffable {
  func diffIdentifier() -> NSObjectProtocol {
    return location.identifier
  }

  func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
    guard self !== object else { return true }
    guard let object = object as? WeatherSectionModel else { return false }
    return location == object.location && forecast == object.forecast && conditions == object.conditions
  }
}
```

#### What if I want to make my Swift structs diffable?

Give [this box](https://github.com/Instagram/IGListKit/issues/35#issuecomment-277503724) a try.

#### I want to deliver messages to certain section controllers, how do I do that?

We recommend using dependency injection and announcing changes, demonstrated in [our example](https://github.com/Instagram/IGListKit/blob/main/Examples/Examples-iOS/IGListKitExamples/ViewControllers/AnnouncingDepsViewController.swift).

#### Should I reuse my section controllers between models?

No! `IGListKit` is designed to have a 1:1 instance mapping between objects and section controllers. `IGListKit` does not reuse section controllers, and if you do unintended behaviors will occur.

`IGListKit` _does_ still use `UICollectionView`'s cell reuse, so you shouldn't be concerned about performance.

#### Why does `UICollectionViewFlowLayout` put everything in a new row?

`UICollectionViewFlowLayout` has its limitations, and it's not well designed to support sections on the same "line". Instead you should use [`IGListCollectionViewLayout`](https://github.com/Instagram/IGListKit/blob/main/Source/IGListCollectionViewLayout.h).

#### What if I just want a section controller and don't need the object?

Feel free to use a static string or number as your model. You can use this object as a "key" to find your section controller. Take a look at our [example](https://github.com/Instagram/IGListKit/blob/main/Examples/Examples-iOS/IGListKitExamples/ViewControllers/SearchViewController.swift#L34) of this.

#### How do I make my cells diff and animate?

Use [`IGListBindingSectionController`](https://github.com/Instagram/IGListKit/blob/main/Source/IGListBindingSectionController.h) to automatically diff and animate your cells.

#### How can I power and update the number of items in a section controller with a dynamic array?

We recommend creating a model that owns an array to the items that power `numberOfItems`. Checkout our [Post example](https://github.com/Instagram/IGListKit/blob/main/Examples/Examples-iOS/IGListKitExamples/SectionControllers/PostSectionController.m#L32) that has dynamic comment cells. Just be sure to check when your array changes:

```swift
class Forecast: ListDiffable {
  let day: Date
  let hourly: [HourlyForecast]

  func diffIdentifier() -> NSObjectProtocol {
    return day
  }

  func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
    guard self !== object else { return true }
    guard let object = object as? Forecast else { return false }
    return hourly == object.hourly // compare elements in the arrays
  }
}
```

---

### Guides Generating Your Models Using Remodel (`Guides/Generating your models using remodel.md`)

# Generating your IGListDiffable models using remodel

With the `IGListDiffable` plugin for [remodel by facebook](https://github.com/facebook/remodel), you can automatically generate models conforming to the `IGListDiffable`.

This will automatically implement `hash`, `isEqual:` and `description`, as well as `diffIdentifier` and `isEqualToDiffableObject:` for you. Remodel is also capable to generate additional code, like conforming to `NSCoding` or additional Builder classes for your model object. It will make creating and updating models much easier, faster and safer.

In `/remodel-plugin`, you can find the source files to build the `IGListDiffable` plugin locally.

## Installation

### 1. Remodel installation

Please follow the [installation instructions](https://github.com/facebook/remodel) in the main remodel repository.

tl;dr: Either clone the original repository, or use an npm installation. In the latter case you can run `which remodel-gen` to find out the path of your installation.

### 2. Plugin installation

Copy the following files & folders within `/remodel-plugin` into your local remodel checkout:

- `/src/plugins/iglistdiffable.ts` - the actual plugin
- `/src/__tests__/plugins/iglistdiffable-test.ts` - unit tests
- `/features/iglistdiffable.feature` - integration tests

And then register the new plugin with the system:

- Edit `/remodel/src/value-object-default-config.ts` and add `iglistdiffable` to the list of basePlugins:

```
// value-object-default-config.ts
basePlugins: List.of(
    'assert-nullability',
    'assume-nonnull',
    'builder',
    'coding',
    'copying',
    'description',
    'equality',
    'fetch-status',
    'immutable-properties',
    'init-new-unavailable',
    'use-cpp',
    'iglistdiffable'
  )
```

### 3. Build plugin:

Once you copied them over and registered the plugin, you have to compile the typescript files into javascript. Do do so run this command from the remodel directory:

- `./bin/build`

### 4. Run tests (optional)

To run the unit/integration tests, you can run the following commands:

- `./bin/runUnitTests`
- `./bin/runAcceptanceTests`

This is especially useful if you plan to change/extend the plugin in any way.

### 5. Use the plugin

Now you are ready to generate your `IGListDiffable` conforming models! To generate a model, create a new `.value` file. Here's an example:

```
# PersonModel.value
PersonModel includes(IGListDiffable) {
  NSString *firstName
  NSString *lastName
  %diffIdentifier
  NSString *uniqueId
}
```

To generate your Objective-C models, run the generation tool like this:

`./bin/generate path/to/your/PersonModel.value`

This will generate the following Objective-C files in the same directory:

```
// PersonModel.h
@interface PersonModel : NSObject <IGListDiffable, NSCopying>

@property (nonatomic, readonly, copy) NSString *firstName;
@property (nonatomic, readonly, copy) NSString *lastName;
@property (nonatomic, readonly, copy) NSString *uniqueId;

- (instancetype)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName uniqueId:(NSString *)uniqueId;

@end
```

and

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Documentation

Please see the main remodel repository for [additional documentation](https://github.com/facebook/remodel)

---

### Guides Getting Started (`Guides/Getting Started.md`)

# Getting Started

This guide provides a brief overview for how to get started using `IGListKit`.

## Creating your first list

After installing `IGListKit`, creating a new list is easy.

### Creating a section controller

Creating a new section controller is simple. Subclass `IGListSectionController` and override at least `cellForItemAtIndex:` and `sizeForItemAtIndex:`.

Take a look at [LabelSectionController](https://raw.githubusercontent.com/Instagram/IGListKit/main/Examples/Examples-iOS/IGListKitExamples/SectionControllers/LabelSectionController.swift) for an example section controller that handles a `String` and configures a single cell with a `UILabel`.

```swift
class LabelSectionController: ListSectionController {
  override func sizeForItem(at index: Int) -> CGSize {
    return CGSize(width: collectionContext!.containerSize.width, height: 55)
  }

  override func cellForItem(at index: Int) -> UICollectionViewCell {
    return collectionContext!.dequeueReusableCell(of: MyCell.self, for: self, at: index)
  }
}
```

### Creating the UI

After creating at least one section controller, you must create a `UICollectionView` and `IGListAdapter`.

```swift
let layout = UICollectionViewFlowLayout()
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)

let updater = ListAdapterUpdater()
let adapter = ListAdapter(updater: updater, viewController: self)
adapter.collectionView = collectionView
```

> **Note:** This example is done within a `UIViewController` and uses both a stock `UICollectionViewFlowLayout` and `IGListAdapterUpdater`. You can use your own layout and updater if you need advanced features!

### Connecting the data source

The last step is the `IGListAdapter`'s data source and returning some data.

```swift
func objects(for listAdapter: ListAdapter) -> [ListDiffable] {
  // this can be anything!
  return [ "Foo", "Bar", 42, "Biz" ]
}

func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController {
  if object is String {
    return LabelSectionController()
  } else {
    return NumberSectionController()
  }
}

func emptyView(for listAdapter: ListAdapter) -> UIView? {
  return nil
}
```

After you have created the data source you need to connect it to the `IGListAdapter` by setting its `dataSource` property:

```swift
adapter.dataSource = self
```

You can return an array of _any_ type of data, as long as it conforms to `IGListDiffable`.

### Immutability

The data should be immutable. If you return mutable objects that you will be editing later, `IGListKit` 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 `IGListDiffable`.

## Diffing

`IGListKit` uses an algorithm adapted from a paper titled [A technique for isolating differences between files](http://dl.acm.org/citation.cfm?id=359467&dl=ACM&coll=DL) by Paul Heckel. This algorithm uses a technique known as the *longest common subsequence* to find a minimal diff between collections in linear time `O(n)`. It finds all **inserts**, **deletes**, **updates**, and **moves** between arrays of data.

To add custom, diffable models, you need to conform to the `IGListDiffable` protocol and implement `diffIdentifier()` and `isEqual(toDiffableObject:)`.

> **Note:** an object's `diffIdentifier()` should never change. If an object mutates it's `diffIdentifer()` the behavior of IGListKit is undefined (and almost assuredly undesirable).

For an example, consider the following model:

```swift
class User {
  let primaryKey: Int
  let name: String
  // implementation, etc
}
```

The user's `primaryKey` uniquely identifies user data, and the `name` is just the value for that user.

Let's say a server returns a `User` object that looks like this:

```swift
let shayne = User(primaryKey: 2, name: "Shayne")
```

But sometime after the client receives `shayne`, someone changes their name:

```swift
let ann = User(primaryKey: 2, name: "Ann")
```

Both `shayne` and `ann` represent the same *unique* data because they share the same `primaryKey`, but they are not *equal* because their names are different.

To represent this in `IGListKit`'s diffing, add and implement the `IGListDiffable` protocol:

```swift
extension User: ListDiffable {
  func diffIdentifier() -> NSObjectProtocol {
    return primaryKey
  }

  func isEqual(toDiffableObject object: Any?) -> Bool {
    if let object = object as? User {
      return name == object.name
    }
    return false
  }
}
```

The algorithm will skip updating two `User` objects that have the same `primaryKey` and `name`, even if they are different instances! You now avoid unnecessary UI updates in the collection view even when providing new instances.

> **Note:** Remember that `isEqual(toDiffableObject:)` should return `false` when you want to reload the cells in the corresponding section controller.

### Diffing outside of IGListKit

If you want to use the diffing algorithm outside of `IGListAdapter` and `UICollectionView`, you can! The diffing algorithm was built with the flexibility to be used with any models that conform to `IGListDiffable`.

```swift
let result = ListDiff(oldArray: oldUsers, newArray: newUsers, .equality)
```

With this you have all of the deletes, reloads, moves, and inserts! There's even a function to generate `NSIndexPath` results.

## Advanced Features

### Working Range

A *working range* is a range of section controllers who aren'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 **prepare content** before they come on screen (e.g. download images).

The `IGListAdapter` 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.

```swift
let adapter = ListAdapter(updater: ListAdapterUpdater(),
                   viewController: self,
                 workingRangeSize: 1) // 1 before/after visible objects
```



You can set the weak `workingRangeDelegate` on a section controller to receive events.

### Supplementary Views

Adding supplementary views to section controllers is as simple as setting the (weak) `supplementaryViewSource` and implementing the `IGListSupplementaryViewSource` protocol. This protocol works nearly the same as returning and configuring cells.

### Display Delegate

Section controllers can set the weak `displayDelegate` delegate to an object, including `self`, to receive display events about a section controller and individual cells.

### Custom Updaters

The default `IGListAdapterUpdater` should handle any `UICollectionView` 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 `IGListUpdatingDelegate` protocol and initialize a new `IGListAdapter` with it.

Check out the updater `IGListReloadDataUpdater` (used in unit tests) for an example.

---

### Guides IGListDiffable And Equality (`Guides/IGListDiffable and Equality.md`)

# IGListDiffable and Equality

This guide explains the `IGListDiffable` protocol and how to write good `-isEqual:` methods. 

## Background

The [`IGListDiffable` protocol](https://instagram.github.io/IGListKit/Protocols/IGListDiffable.html) requires clients to implement two methods, `-diffIdentifier` and `-isEqualToDiffableObject:`.

The method `-isEqualToDiffableObject:` should perform the same type of check as `-isEqual:`, but without impacting performance characteristics, like in Objective-C containers such as `NSDictionary` and `NSSet`.

Why are both of these methods required for diffing? The point of having the two methods has to do with **identity** and **equality**, where the diff identifier uniquely identifies data (common scenario is primary key in databases). Equality comes into play when comparing the values of two uniquely identical objects (driving reloading).

See also: [#509](https://github.com/Instagram/IGListKit/issues/509)

## `IGListDiffable` bare minimum

The quickest way to get started with diffable models is use the _object itself_ as the identifier, and use the superclass's `-[NSObject isEqual:]` implementation for equality:

```objc
- (id<NSObject>)diffIdentifier {
  return self;
}

- (BOOL)isEqualToDiffableObject:(id<IGListDiffable>)object {
  return [self isEqual:object];
}
```

## Writing better Equality methods

Even though `IGListKit` uses the method `-isEqualToDiffableObject:`, the concepts of writing a good equality check apply in general. Here are the basics to writing good `-isEqual:` and `-hash` functions. Note this is all Objective-C but applies to Swift also.

- If you override `-isEqual:` you **must** override `-hash`. Check out this [article by Mike Ash](https://www.mikeash.com/pyblog/friday-qa-2010-06-18-implementing-equality-and-hashing.html) for details.
- Always compare the pointer first. This saves a lot of wasteful `objc_msgSend(...)` calls and value comparisons if checking the same instance.
- When comparing object values, always check for `nil` before `-isEqual:`. For example, `[nil isEqual:nil]` counterintuitively returns `NO`. Instead, do `left == right || [left isEqual:right]`.
- Always compare the **cheapest values first**. For example, doing `[self.array isEqual:other.array] && self.intVal == other.intVal` is extremely wasteful if the `intVal` values are different. Use lazy evaluation!

As an example, if I had a `User` model with the following interface:

```objc
@interface User : NSObject

@property NSInteger identifier;
@property NSString *name;
@property NSArray *posts;

@end
```

You would implement its equality methods like so:

```objc
@implementation User

- (NSUInteger)hash {
  return self.identifier;
}

- (BOOL)isEqual:(id)object {
  if (self == object) { 
      return YES;
  }
  
  if (![object isKindOfClass:[User class]]) {
      return NO;
  }

  User *right = object;
  return self.identifier == right.identifier 
      && (self.name == right.name || [self.name isEqual:right.name])
      && (self.posts == right.posts || [self.posts isEqualToArray:right.posts]);
}

@end
```

## Using both `IGListDiffable` and `-isEqual:`

Making your objects work universally with Objective-C containers and `IGListKit` is easy once you've implemented `-isEqual:` and `-hash`.

```objc
@interface User <IGListDiffable>

// properties...

@end

@implementation User

- (id<NSObject>)diffIdentifier {
    return @(self.identifier);
}

- (BOOL)isEqualToDiffableObject:(id<IGListDiffable>)object {
    return [self isEqual:object];
}

@end
```

---

### Guides Installation (`Guides/Installation.md`)

# Installation

This guide provides details on how to install `IGListKit`.

## CocoaPods

The preferred method of installation for `IGListKit` is using [CocoaPods](https://cocoapods.org/).

In order to use the latest release of the framework, add the following to your `Podfile`:

```ruby
pod 'IGListKit', '~> 4.0'
```

### Using `main`

Alternatively, you can use the latest version from the [`main` branch](https://github.com/Instagram/IGListKit/tree/main). This is what we use at Instagram, so you can be confident that `main` is always stable and reliable.

```ruby
pod 'IGListKit', :git => 'https://github.com/Instagram/IGListKit.git', :branch => 'main'
```

> **Note:** while `main` is stable, it may have breaking changes. Before updating to `main`, be sure to check the [`CHANGELOG`](https://github.com/Instagram/IGListKit/blob/main/CHANGELOG.md) for details on changes.

### Subspecs

With the exception of `macOS` (which currently only supports the diffing algorithm components), using `pod 'IGListKit'` will get you the full library, including the flexible `UICollectionView` system. Learn more about how to get started in our [Getting Started guide](https://instagram.github.io/IGListKit/getting-started.html).

However, if you only want to use the diffing components of this library, then you can use the diffing subspec in your `Podfile`:

```ruby
pod 'IGListKit/Diffing', '~> 4.0'
```

Regardless of whether you only use the diffing components, or the entire library, the imports are the same:

```swift
import IGListKit
```

## Carthage

If using [Carthage](https://github.com/Carthage/Carthage), add the following to your `Cartfile`:

```ogdl
github "Instagram/IGListKit" ~> 4.0
```

---

### Guides Migration (`Guides/Migration.md`)

# Migration

This guide provides details for how to migrate between major versions of `IGListKit`.

## From 2.x to 3.x

For details on all changes in IGListKit 3.0.0, please see the [release notes](https://github.com/Instagram/IGListKit/releases/tag/3.0.0). 

> **NOTE:** This release contains *a lot* of improvements and source-breaking API changes, especially for Swift clients. These are all noted in the full [release notes](https://github.com/Instagram/IGListKit/releases/tag/3.0.0).

### "IG" prefix removed for Swift

We have improved how `IGListKit` APIs get imported into Swift. The `IG` prefix has been removed for Swift clients. For example, `IGListSectionController` becomes `ListSectionController` instead. Along with other interoperability improvements, this makes `IGListKit` more readable in Swift.

To migrate, use Xcode's Find navigator (command-3), search for `IGList`, and replace with `List`.

### `IGListSectionType` removed

In order to make building section controllers even easier, we removed the protocol and absorbed all of the methods into `IGListSectionController` with default implementations.

- `numberOfItems` returns 1 item
- `didUpdateToObject:` and `didSelectItemAtIndex:` do nothing
- `sizeForItemAtIndex:` returns `CGSizeZero`
- `cellForItemAtIndex:` asserts (you must override this method)

In Objective-C, all you need to do is find & remove all uses of `IGListSectionType`. This includes `IGListSectionController` and `IGListAdapterDataSource` implementations.

In Swift, you will also need to add `override` keywords to all methods.

The compiler should catch all instances that need fixed.

### `IGListBindingSectionController`

If you were using `IGListDiff(...)` _inside_ a section controller to compute diffs for cells, we recommend that you start using `IGListBindingSectionController` which wraps this behavior in an elegant and tested API.

### Removed `IGListCollectionView`

You can simply find regex `IGListCollectionView([ |\*|\(])` and replace with regex `UICollectionView$1` in your project to fix this.



### Removed `IGListGridCollectionViewLayout`

Start using `IGListCollectionViewLayout` instead of `IGListGridCollectionViewLayout`.

- `scrollDirection` is not yet supported. If you need horizontal scrolling, please use `UICollectionViewFlowLayout` or file an issue.
- Set `minimumLineSpacing` on your [section controllers](https://github.com/Instagram/IGListKit/blob/main/Source/IGListSectionController.h#L59-L64) instead of the layout
- Set `minimumInteritemSpacing` on your [section controllers](https://github.com/Instagram/IGListKit/blob/main/Source/IGListSectionController.h#L66-L71) instead of the layout
- Return the size of your cells in [sizeForItemAtIndex:](https://github.com/Instagram/IGListKit/blob/main/Source/IGListSectionController.h#L48) instead of setting it on the layout.

### Item mutations must be wrapped in `-[IGListCollectionContext performBatchAnimated:completion:]`

To fix some rare crashes, all item mutations must now be performed inside a batch block and done on the `IGListBatchContext` object instead.

**Objective-C**

```objc
// OLD
self.expanded = YES;
[self.collectionContext insertInSectionController:self atIndexes:[NSIndexSet indexSetWithIndex:]];

// NEW
[self.collectionContext performBatchAnimated:YES updates:^(id<IGListBatchContext> batchContext) {
  self.expanded = YES;
  [batchContext insertInSectionController:self atIndexes:[NSIndexSet indexSetWithIndex:1]];
} completion:nil];
```

**Swift**

```swift
// OLD
expanded = true
collectionContext?.insert(in: self, at: [0])

// NEW
collectionContext?.performBatch(animated: true, updates: { (batchContext) in
  self.expanded = true
  batchContext.insert(in: self, at: [0])
})
```

Make sure that your model changes occur **inside the update block**, alongside the context methods.

## From 1.x to 2.x

For details on all changes in `IGListKit` 2.0.0, please see the [release notes](https://github.com/Instagram/IGListKit/releases/tag/2.0.0).

### `IGListDiffable` Conformance

If you relied on the default `NSObject<IGListDiffable>` category, you will need to add `IGListDiffable` conformance to each of your models. To get things working as they did in 1.0, simply add the following to each of your models:

**Objective-C**

```objc
#import <IGListDiffKit/IGListDiffable.h>

// Header
@interface MyModel <IGListDiffable>

// Implementation
- (id<NSObject>)diffIdentifier {
  return self;
}

- (BOOL)isEqualToDiffableObject:(id<IGListDiffable>)object {
  return [self isEqual:object];
}
```

**Swift**

```swift
import IGListKit

extension MyModel: ListDiffable {
  func diffIdentifier() -> NSObjectProtocol {
    return self
  }
  
  func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
    return isEqual(object)
  }
}
```

However we recommend writing more thorough identity and equality checks. Check out our guide to [IGListDiffable and Equality](https://instagram.github.io/IGListKit/iglistdiffable-and-equality.html) for more info.

---

### Guides Modeling And Binding (`Guides/Modeling and Binding.md`)

# Modeling and Binding

This guide will walk you through a practical example of taking an app spec/design and turning it into a working `IGListKit` project.

You will learn how to:

- Turn a design spec into a top-level model and view models
- Use `ListBindingSectionController` for animated, one-way cell updates
- Cell-to-controller action handling and delegation
- Updating the UI with local data mutations

## Getting Started

You can follow along and build the example in this guide. First, you must download [this starter project](https://github.com/rnystrom/IGListKit-Binding-Guide). Open **ModelingAndBinding-Starter/ModelingAndBinding.xcworkspace** since the base project is setup with CocoaPods with `IGListKit` already added as a dependency.

Take a look at the following Instagram-inspired list element design:



You can already start mentally modelling your data:

- The top cell has a **username** and **timestamp** label
- The image cell will need some sort of image `URL`
- An action cell with **like count**. There will also need to be some sort of action handling when someone taps the heart
- Then there are a _dynamic_ number of comment cells that contain a **username** and **comment**

Remember that `IGListKit` functions on **one model per section controller**. All of the cells in this design correlate to one top-level "post" object delivered by a server. You want to create a `Post` model that contains all of the information that the cells require.

> A common mistake is to create a single model and section controller for a single cell. In this example, that will create a **very confusing** architecture since the top-level objects will contain a mix and match of user, image, action, and comment models.

## Creating Models

Create a new file named **Post.swift** in the starter project:

```swift
import IGListKit

final class Post: ListDiffable {

  // 1
  let username: String
  let timestamp: String
  let imageURL: URL
  let likes: Int
  let comments: [Comment]

  // 2
  init(username: String, timestamp: String, imageURL: URL, likes: Int, comments: [Comment]) {
    self.username = username
    self.timestamp = timestamp
    self.imageURL = imageURL
    self.likes = likes
    self.comments = comments
  }

}
```

1. It's best practice to always declare your values as `let` so they cannot be mutated again. The compiler will complain about the `Comment` model, ignore that for now.
2. Since `IGListKit` is compatible with Objective-C, your models must be `class`es which means writing initializers. It's only a little copy & paste!

Now add a `ListDiffable` implementation inside of `Post`:

```swift
// MARK: ListDiffable

func diffIdentifier() -> NSObjectProtocol {
  // 1
  return (username + timestamp) as NSObjectProtocol
}

// 2
func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
  return true
}
```

1. Derive a **unique identifier** for each post. Since a single post should never have the same `username` and `timestamp` combo, we can start with that.
2. A **core requirement** to using `ListBindingSectionController` is that if two models have the same `diffIdentifier`, they **must be equal** so that the section controller can then compare view models.

### View Models

Create a new Swift file named **Comment.swift** and try writing the `Comment` model yourself:

- `username` of type `String`
- `text` of type `String`
- You will be diffing this model eventually, so add a `ListDiffable` implementation

If you get stuck, or just want to copy & paste, you can reveal the implementation below.

<details>
  <summary>Comment implementation</summary>
  <p>

```swift
import IGListKit

final class Comment: ListDiffable {

    let username: String
    let text: String

    init(username: String, text: String) {
        self.username = username
        self.text = text
    }

    // MARK: ListDiffable

    func diffIdentifier() -> NSObjectProtocol {
        return (username + text) as NSObjectProtocol
    }

    func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
        return true
    }

}
```

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>

Using the `Comment` array on a `Post` should make some sense: there are a dynamic number of comments on each post. For each comment, you want to display a cell.

What might be a little bit of a new concept, though, is that you need to create models for the `UserCell`, `ImageCell`, _and_ `ActionCell` as well when working with `ListBindingSectionController`.

> A binding section controller is almost like a mini-`IGListKit`. 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 `ListBindingSectionController` instance.

With that in mind, let's start with the model for the `UserCell`:

Create a new Swift file called **UserViewModel.swift**:

```swift
import IGListKit

final class UserViewModel: ListDiffable {

  let username: String
  let timestamp: String

  init(username: String, timestamp: String) {
    self.username = username
    self.timestamp = timestamp
  }

  // MARK: ListDiffable

  func diffIdentifier() -> NSObjectProtocol {
    // 1
    return "user" as NSObjectProtocol
  }

  func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
    // 2
    guard let object = object as? UserViewModel else  { return false }
    return username == object.username
    && timestamp == object.timestamp
  }

}
```

1. Since there will only be **one `UserViewModel` per `Post`**, you can hardcode an identifier. This will enforce only a single model & cell being used.
2. 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.

Try to make view models for the **image** and **action** cell. Remember there is only a single cell per `Post`, so you can use `UserViewModel` as a starting point for how the models should look.

<details>
  <summary>View model implementations</summary>
  <p>

```swift
import IGListKit

final class ImageViewModel: ListDiffable {

  let url: URL

  init(url: URL) {
    self.url = url
  }

  // MARK: ListDiffable

  func diffIdentifier() -> NSObjectProtocol {
    return "image" as NSObjectProtocol
  }

  func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
    guard let object = object as? ImageViewModel else { return false }
    return url == object.url
  }

}

final class ActionViewModel: ListDiffable {

  let likes: Int

  init(likes: Int) {
    self.likes = likes
  }

  // MARK: ListDiffable

  func diffIdentifier() -> NSObjectProtocol {
    return "action" as NSObjectProtocol
  }

  func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
    guard let object = object as? ActionViewModel else { return false }
    return likes == object.likes
  }
  
}
```

> 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></details>

## Using ListBindingSectionController

You now have the following view models, which can all be derived from each `Post`:

- `UserViewModel`
- `ImageViewModel`
- `ActionViewModel`
- `Comment`

Let's start using these models to power cells using `ListBindingSectionController`. This controller takes a top-level model (`Post`), 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).



Create **PostSectionController.swift** and add the following code:

```swift
final class PostSectionController: ListBindingSectionController<Post>,
ListBindingSectionControllerDataSource {

  override init() {
    super.init()
    dataSource = self
  }

}
```

Notice that you are subclassing `ListBindingSectionController<Post>`. This declares your section controller as receiving a `Post` model. That way you don't have to do any special casting of your model.

There are 3 methods that are required to satisfy the data source protocol:

- Return an array of view models given the top-level model (`Post`)
- Return a size for a given view model
- Return a cell for a given view model

First take care of the `Post`-to-view-models transformation:

```swift
// MARK: ListBindingSectionControllerDataSource

func sectionController(
  _ sectionController: ListBindingSectionController<ListDiffable>,
  viewModelsFor object: Any
  ) -> [ListDiffable] {
    // 1
    guard let object = object as? Post else { fatalError() }
    // 2
    let results: [ListDiffable] = [
      UserViewModel(username: object.username, timestamp: object.timestamp),
      ImageViewModel(url: object.imageURL),
      ActionViewModel(likes: object.likes)
    ]
    // 3
    return results + object.comments
}
```

1. The `object` property **must** be optional because it will not exist upon section controller initialization. However, it should never be nil at this point, nor should the `object: Any` parameter be anything but the section controller type. This is a limitation of Objective-C generics and protocols, so doing a `fatalError()` here is appropriate.
2. Create your array of view models by _decomposing_ the `Post` model into smaller models.
3. You can even append dynamic models that are delivered from the server.

Next add the required API to return a size for each view model:

```swift
func sectionController(
  _ sectionController: ListBindingSectionController<ListDiffable>,
  sizeForViewModel viewModel: Any,
  at index: Int
  ) -> CGSize {
  // 1
  guard let width = collectionContext?.containerSize.width else { fatalError() }
  // 2
  let height: CGFloat
  switch viewModel {
  case is ImageViewModel: height = 250
  case is Comment: height = 35
  // 3
  default: height = 55
  }
  return CGSize(width: width, height: height)
}
```

1. Just like the `object` property, the `collectionContext` should never be `nil`, but it's a weakly referenced object so must be declared as optional. Again, use `fatalError()` to catch any critical failures.
2. Swift makes checking for types so easy! Just `switch` on the type and assign a height. In Objective-C you should use `isKindOfClass:`.
3. Both the `UserViewModel` and `ActionViewModel` share the same height of `55`pts according to the design.

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.

> Remember that the cells are defined in **Main.storyboard**. You can click on each cell to view their identifiers.

<details>
  <summary>"cellForViewModel:" implementation</summary>
  <p>

```swift
func sectionController(
  _ sectionController: ListBindingSectionController<ListDiffable>,
  cellForViewModel viewModel: Any,
  at index: Int
  ) -> UICollectionViewCell {
  let identifier: String
  switch viewModel {
  case is ImageViewModel: identifier = "image"
  case is Comment: identifier = "comment"
  case is UserViewModel: identifier = "user"
  default: identifier = "action"
  }
  guard let cell = collectionContext?
    .dequeueReusableCellFromStoryboard(withIdentifier: identifier, for: self, at: index)
    else { fatalError() }
  return cell
}
```

Remember to handle `UserViewModel` and `ActionViewModel` separately!

</p></details>

## Binding Models to Cells

Now you have `PostSectionController` setup to create view models, sizes, and cells. The last piece to using `ListBindingSectionController` is having your cells to receive its assigned view model and configure itself. 

This is done by making your cells conform to `ListBindable`. With that, `ListBindingSectionController` will **automatically** bind view models to each cell!

Open **ImageCell.swift** and change the implementation to look like the following:

```swift
import UIKit
import SDWebImage
// 1
import IGListKit

// 2
final class ImageCell: UICollectionViewCell, ListBindable {

  @IBOutlet weak var imageView: UIImageView!

  // MARK: ListBindable

  func bindViewModel(_ viewModel: Any) {
    // 3
    guard let viewModel = viewModel as? ImageViewModel else { return }
    // 4
    imageView.sd_setImage(with: viewModel.url)
  }

}
```

1. Make sure to import `IGListKit`!
2. Have the cell conform to `ListBindable`
3. Guard against the view model type. This will always be what `PostSectionController` pairs the cell with in `cellForViewModel:`, but guard to be safe.
4. Use the [SDWebImage](https://github.com/rs/SDWebImage) library to set the image URL.

Now do exactly the same thing for each of the other cells:

- `ActionCell` binds `ActionViewModel`
- `UserCell` binds `UserViewModel`
- `CommentCell` binds `Comment`

<details>
  <summary>ListBindable implementations</summary>
  <p>

```swift
final class ActionCell: UICollectionViewCell, ListBindable {

  @IBOutlet weak var likesLabel: UILabel!
  @IBOutlet weak var likeButton: UIButton!

  // MARK: ListBindable

  func bindViewModel(_ viewModel: Any) {
    guard let viewModel = viewModel as? ActionViewModel else { return }
    likesLabel.text = "\(viewModel.likes)"
  }

}

final class UserCell: UICollectionViewCell, ListBindable {

  @IBOutlet weak var usernameLabel: UILabel!
  @IBOutlet weak var dateLabel: UILabel!

  // MARK: ListBindable

  func bindViewModel(_ viewModel: Any) {
    guard let viewModel = viewModel as? UserViewModel else { return }
    usernameLabel.text = viewModel.username
    dateLabel.text = viewModel.timestamp
  }

}

final class CommentCell: UICollectionViewCell, ListBindable {

  @IBOutlet weak var usernameLabel: UILabel!
  @IBOutlet weak var commentLabel: UILabel!

  // MARK: ListBindable

  func bindViewModel(_ viewModel: Any) {
    guard let viewModel = viewModel as? Comment else { return }
    usernameLabel.text = viewModel.username
    commentLabel.text = viewModel.text
  }

}
```
</p></details>

## Displaying in the View Controller

The very last step is getting the `PostSectionController` displaying in the app's list.

Go back to **ViewController.swift** and add the following to `viewDidLoad()`, **before** setting the `dataSource` or `collectionView`:

```swift
data.append(Post(
  username: "@janedoe",
  timestamp: "15min",
  imageURL: URL(string: "https://placekitten.com/g/375/250")!,
  likes: 384,
  comments: [
    Comment(username: "@ryan", text: "this is beautiful!"),
    Comment(username: "@jsq", text: "😱"),
    Comment(username: "@caitlin", text: "#blessed"),
  ]
))
```

Lastly, update `listAdapter(_, sectionControllerFor object:)`:

```swift
func listAdapter(
  _ listAdapter: ListAdapter,
  sectionControllerFor object: Any
  ) -> ListSectionController {
  return PostSectionController()
}
```

> Normally you'd want to check the type of `object`, but since you're only using `Post` at this point, it's safe to simply return a new `PostSectionController`.

**Build and run** the sample app to see your post show up!



## Handling Cell Actions

This design should respond to tapping the heart icon on the `ActionCell`. In order to do that, you need to handle taps on the `UIButton`, then forward the event to the `PostSectionController`:

Open **ActionCell.swift** and add the following protocol:

```swift
protocol ActionCellDelegate: AnyObject {
  func didTapHeart(cell: ActionCell)
}
```

Add a new delegate variable to the `ActionCell`, beneath the outlets:

```swift
weak var delegate: ActionCellDelegate? = nil
```

Override `awakeFromNib()` and add a target & action to the `likeButton`:

```swift
override func awakeFromNib() {
  super.awakeFromNib()
  likeButton.addTarget(self, action: #selector(ActionCell.onHeart), for: .touchUpInside)
}
```

The last thing you need to do in **ActionCell.swift** is add an implementation for `onHeart()`:

```swift
func onHeart() {
  delegate?.didTapHeart(cell: self)
}
```

This will forward the button tap outside of the cell and to the delegate.

Open **PostSectionController.swift** and update the `cellForViewModel:` method. Add the following at the end of the method, just after the `guard` and right before you return the `cell`:

```swift
if let cell = cell as? ActionCell {
  cell.delegate = self
}
```

The compiler will immediately complain. Satisfy the compiler but adding an empty implementation to `PostSectionController`:

```swift
final class PostSectionController: ListBindingSectionController<Post>,
ListBindingSectionControllerDataSource,
ActionCellDelegate {

//...

// MARK: ActionCellDelegate

func didTapHeart(cell: ActionCell) {
  print("like")
}
```

**Build and run** the app and tap on the heart button. You should see "like"s printing into the console.

## Local Mutations

Every time someone taps the heart button, you need to add a new like to the `Post`. However, all of your models are declared with `let` because immutable models are a much safer design. But if everything is immutable, how do we mutate the like count?

The `PostSectionController` is the _perfect_ place to handle and store mutations. Open **PostSectionController.swift** and add the following variable:

```swift
var localLikes: Int? = nil
```

Go back to the `didTapHeart(cell:)` delegate method and change the implementation to the following:

```swift
func didTapHeart(cell: ActionCell) {
  // 1
  localLikes = (localLikes ?? object?.likes ?? 0) + 1
  // 2
  update(animated: true)
}
```

1. Mutate the `localLikes` variable using either the previous `localLikes` or starting with `object.likes`, whichever exists. Fallback to `0` which will never happen, just satisfying the compiler.
2. Call the `update(animated:,completion:)` API on `ListBindingSectionController` to refresh the cells on the screen.

In order to actually send the mutations to the models, you need to start using `localLikes` with the `ActionViewModel` which is given to the `ActionCell`.

Still in **PostSectionController.swift**, find the `cellForViewModel:` API and change the `ActionViewModel` initialization to the following:

```swift
ActionViewModel(likes: localLikes ?? object.likes)
```

**Build and run** the app, tap on the heart button, and see your likes increment!

<p align="center">
  <img src="https://raw.githubusercontent.com/Instagram/IGListKit/main/Resources/modeling-likes.gif" width=300  />
</p>

## Wrapping up

If you got stuck at all, or just want to play around with the example, you can find the finished project [here](https://github.com/rnystrom/IGListKit-Binding-Guide) in **ModelingAndBinding/ModelingAndBinding.xcworkspace**.

`ListBindingSectionController` is one of the most powerful features that we've built for `IGListKit` because it further encourages you to design small, composable models, views, and controllers.

You can also use the section controller to handle any interactions, as well as deal with mutations, just like a controller should!

If you have suggestions for other topics you'd like to see, or want to offer a correction, please create a [new issue](https://github.com/Instagram/IGListKit/issues/new)!

---

### Guides VISION (`Guides/VISION.md`)

# Vision

This document serves to outline the long term goals of `IGListKit` and act as a guidance when making decisions about features and issues.

## Prioritizing Features & Fixes

`IGListKit` is a data-driven, list-building framework built, owned, and maintained by the engineering team at Instagram. Because `IGListKit` powers parts of the Instagram iOS app, we prioritize features and bugs towards those that affect Instagram. However the team recognizes the wide range of use-cases for `IGListKit` and wants to serve as broad an audience as possible without sacrificing our own needs.

## Goals & Scope

The core goal of `IGListKit` is to build fast, stable, and data-driven lists in iOS applications. That scope includes things like:

- `UICollectionView` and `UITableView` integrations
- Data and state management
- Diffing algorithms

While `IGListKit` uses specific tools, we do want to limit the reach of how we use those tools. We highly encourage people to explore solutions that fit their needs and will try to assist when possible. Examples of things beyond the scope of `IGListKit`:

- Advanced/custom `UICollectionViewLayout`s
- Sizing and layout (e.g. auto layout, estimated sizes)
- Render and display pipelines
- Integration with third-parties

## Collaboration & Community

While `IGListKit` is an Instagram project, we want to give as much ownership and responsibility to the community as possible. We welcome everyone to become a collaborator on the project with whatever level of contribution you feel comfortable with.

We recognize that maintaining open source projects can be demanding, and often done in addition to other responsibilities. We have no expectation for the amount or frequency of contribution from anyone.

We also ask that you help keep our community welcoming and open.

## Communication

GitHub Issues serve as the "source of truth" for all communication and decision-making about `IGListKit`. This keeps everything open and centralized. We will consider other forms of communication (Slack, Facebook Group, etc) once the scale of the project and/or community demands it.

---

### Guides Working With Core Data (`Guides/Working with Core Data.md`)

# Working with Core Data

This guide provides details on how to work with [Core Data](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/index.html) and `IGListKit`.

## Background

The main difference in the setup and architecture of a Core Data and `IGListKit` application is the configuration of the model layer. Core Data operates with a mutable model layer, where objects are always passed by reference and the same instance is modified when an object is edited.

`IGListKit` requires an immutable model in order to correctly calculate the diffing between model snapshots and to correctly animate the `UICollectionView`.

In order to satisfy these prerequisites, Core Data `NSManagedObject`s should not be used directly as `ListDiffable` objects. Instead, a view model (or some sort of token object) should be used to mimic (or act as a placeholder for) the data that will be displayed in the collection view.

## Further discussion

There are further discussions on this topic at [#460](https://github.com/Instagram/IGListKit/issues/460), [#461](https://github.com/Instagram/IGListKit/issues/461), [#407](https://github.com/Instagram/IGListKit/issues/407).

## Basic Setup

The basic setup for Core Data and `IGListKit` is the same as the normal setup that is found in the [Getting Started Guide](https://instagram.github.io/IGListKit/getting-started.html). The main difference will be in the setup of the model used in the `IGListAdapterDataSource`.

## Working with view model

### Creating a view model

Suppose the Core Data model consist of:

```swift
extension User {
    @NSManaged var firstName: String
    @NSManaged var lastName: String
    @NSManaged var address: String
    @NSManaged var someVariableNotNeededInUI: String
}
```

A `ViewModel` object will contain only the necessary information needed to build UI. The properties of the `ViewModel` will be immutable:

```swift
class UserViewModel: NSObject {
    let firstName: String
    let lastName: String
    let address: String
}
```

We recommend writing a helper method to translate Core Data objects into `ViewModel` objects:

```swift
extension UserViewModel {
    static func fromCoreData(user: User) -> UserViewModel {
        // - Note: For avoiding Core Data threading violation, the following code should be wrapped in a
        // user.managedObjectContext?.performAndWait {}
        return UserViewModel(firstName: user.firstName, lastName: user.lastName, address: user.lastName)
    }
}
```

The `IGListDiffable` protocol is implemented on the `ViewModel` layer:

```swift
extension UserViewModel: ListDiffable {

    public func diffIdentifier() -> NSObjectProtocol {
        return NSString(string: firstName + lastName)
    }

    public func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
        guard let toObject = object as? UserViewModel else { return false }

        return self.firstName == toObject.firstName
            && self.lastName == toObject.lastName
            && self.address == toObject.address
    }
}
```

## Setting up the view model in the adapter data source

Steps to configure the `UICollectionView` with the `ViewModel`:

- Retrieve Core Data objects
- Transform Core Data objects into ViewModel objects and return them
- Track changes to Core Data objects and update the datasource with them

### Retrieve Core Data objects

The way objects are retrieved from Core Data is depends on the project. 

Example: Suppose there is a delegate `Provider` class with the role of fetching Core Data objects and checking for updates. It can use an `NSFetchedResultsController` to leverage on the Core Data framework and rely on automatic notifications for updates.

```swift
final class UserProvider: NSObject {

    private lazy var userFetchResultController: NSFetchedResultsController<User> = {
        let fetchRequest: NSFetchRequest<User> = NSFetchRequest(entityName: "User")

        // sort descriptors and predicates 
        // ...
    
        let fetchResultController = NSFetchedResultsController(
           fetchRequest: tripsFetchRequest,
           managedObjectContext: self.coreDataStack.mainQueueManagedObjectContext,
           sectionNameKeyPath: nil,
           cacheName: nil)

        // Set delegate to track CoreData changes
        fetchResultController.delegate = self

        return fetchResultController
    }()

    init(coreDataStack: CoreDataStack) {
        self.coreDataStack = coreDataStack
        super.init()
        do {
            try userFetchResultController.performFetch()
        }
        catch {
            fatalError("Cannot Fetch! \(error)")
        }
    }
}
```

### Transform Core Data objects into view models

```swift
func getUsers() -> [UserViewModel]? {
    guard let users = self.userFetchResultController.fetchedObjects else { return nil }
    // Here we transform and return ViewModel objects!
    return users.flatMap { UserViewModel.fromCoreData(user: $0) }
}
```

### Track changes to Core Data

The `Provider` will track changes to the Core Data model by listening to the `NSFetchedResultsController` methods and inform the application about this changes via KVO, notifications, delegation, etc.

```swift
extension UserProvider: NSFetchedResultsControllerDelegate {
    func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
        self.delegate?.performUpdatesForCoreDataChange(animated: true)
    }
}
```

### Configure the datasource

The data source retrieves ViewModels and configures the `IGListSectionController` with them:

```swift
func objects(for listAdapter: ListAdapter) -> [ListDiffable] {
    return self.userProvider.getUsers()
}
```

### Reacting to Core Data changes in UI

The `UIViewController` containing the `UICollectionView`, will react to the `NSFetchedResultController` messages by updating the UI:

```swift
func performUpdatesForCoreDataChange(animated: Bool) {
    // Updating contents of collection view
    self.adapter.performUpdates(animated: animated)
}
```

---

### Guides Working With UICollectionView (`Guides/Working with UICollectionView.md`)

# Working with `UICollectionView`

This guide provides details on how to work with [`UICollectionView`](https://developer.apple.com/reference/uikit/uicollectionview) and `IGListKit`.

## Background

Early versions of `IGListKit` (2.x and prior) shipped with a subclass of `UICollectionView` called [`IGListCollectionView`](https://github.com/Instagram/IGListKit/blob/2.1.0/Source/IGListCollectionView.h). The class contained *no* special functionality and was merely used to enforce compile-time restrictions to prevent users from calling certain methods directly on `UICollectionView`. Beginning with 3.0, `IGListCollectionView` [was removed](https://github.com/Instagram/IGListKit/commit/2284ce389708f62d99f48ff2ec15644f1ec59537) for a number of reasons.

For further discussion see [#240](https://github.com/Instagram/IGListKit/issues/240) and [#409](https://github.com/Instagram/IGListKit/issues/409).

## Methods to avoid

One of the primary purposes of `IGListKit` is to perform optimal batch updates for `UICollectionView`. Thus, clients **should never** call any APIs on `UICollectionView` that involved reloading, inserting, deleting, or otherwise updating cells and index paths. Instead, use the APIs provided by [`IGListAdapter`](https://instagram.github.io/IGListKit/Classes/IGListAdapter.html). You should also avoid setting the [`delegate`](https://developer.apple.com/reference/uikit/uicollectionview/1618033-delegate) and [`dataSource`](https://developer.apple.com/reference/uikit/uicollectionview/1618091-datasource) of the collection view, as this is also the responsibility of `IGListAdapter`.

Avoid calling the following methods:

```objc
- (void)performBatchUpdates:(void (^)(void))updates
                 completion:(void (^)(BOOL))completion;

- (void)reloadData;

- (void)reloadSections:(NSIndexSet *)sections;

- (void)insertSections:(NSIndexSet *)sections;

- (void)deleteSections:(NSIndexSet *)sections;

- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection;

- (void)insertItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths;

- (void)reloadItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths;

- (void)deleteItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths;

- (void)moveItemAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath;

- (void)setDelegate:(id<UICollectionViewDelegate>)delegate;

- (void)setDataSource:(id<UICollectionViewDataSource>)dataSource;

- (void)setBackgroundView:(UIView *)backgroundView;
```

## Performance

In iOS 10, a new [cell prefetching API](https://developer.apple.com/reference/uikit/uicollectionviewdatasourceprefetching) was introduced. At Instagram, enabling this feature substantially degraded scrolling performance. We recommend setting [`isPrefetchingEnabled`](https://developer.apple.com/reference/uikit/uicollectionview/1771771-isprefetchingenabled) to `NO` (`false` in Swift). Note that the default value is `true`.

You can set this globally using `UIAppearance`:

```objc
if ([[UICollectionView class] instancesRespondToSelector:@selector(setPrefetchingEnabled:)]) {
    [[UICollectionView appearance] setPrefetchingEnabled:NO];
}
```

```swift
if #available(iOS 10, *) {
    UICollectionView.appearance().isPrefetchingEnabled = false
}
```

---

### Search.Json (`docs/search.json`)

{"Structs/IGListCollectionScrollingTraits.html#/c:@S@IGListCollectionScrollingTraits@FI@isTracking":{"name":"isTracking","abstract":"\u003cp\u003ereturns YES if user has touched. may not yet have started dragging.\u003c/p\u003e","parent_name":"IGListCollectionScrollingTraits"},"Structs/IGListCollectionScrollingTraits.html#/c:@S@IGListCollectionScrollingTraits@FI@isDragging":{"name":"isDragging","abstract":"\u003cp\u003ereturns YES if user has started scrolling. this may require some time and or distance to move to initiate dragging\u003c/p\u003e","parent_name":"IGListCollectionScrollingTraits"},"Structs/IGListCollectionScrollingTraits.html#/c:@S@IGListCollectionScrollingTraits@FI@isDecelerating":{"name":"isDecelerating","abstract":"\u003cp\u003ereturns YES if user isn\u0026rsquo;t dragging (touch up) but scroll view is still moving.\u003c/p\u003e","parent_name":"IGListCollectionScrollingTraits"},"Structs/IGListAdaptiveCoalescingExperimentConfig.html#/c:@S@IGListAdaptiveCoalescingExperimentConfig@FI@enabled":{"name":"enabled","abstract":"\u003cp\u003eEnable adaptive coalescing, where we try to mininimize the update delay\u003c/p\u003e","parent_name":"IGListAdaptiveCoalescingExperimentConfig"},"Structs/IGListAdaptiveCoalescingExperimentConfig.html#/c:@S@IGListAdaptiveCoalescingExperimentConfig@FI@minInterval":{"name":"minInterval","abstract":"\u003cp\u003eStart coalescing if the last update was within this interval\u003c/p\u003e","parent_name":"IGListAdaptiveCoalescingExperimentConfig"},"Structs/IGListAdaptiveCoalescingExperimentConfig.html#/c:@S@IGListAdaptiveCoalescingExperimentConfig@FI@intervalIncrement":{"name":"intervalIncrement","abstract":"\u003cp\u003eIf we need to coalesce, increase the interval by this much for next time.\u003c/p\u003e","parent_name":"IGListAdaptiveCoalescingExperimentConfig"},"Structs/IGListAdaptiveCoalescingExperimentConfig.html#/c:@S@IGListAdaptiveCoalescingExperimentConfig@FI@maxInterval":{"name":"maxInterval","abstract":"\u003cp\u003eThis is the maximum coalesce interval, so the slowest and update can wait.\u003c/p\u003e","parent_name":"IGListAdaptiveCoalescingExperimentConfig"},"Structs/IGListAdaptiveCoalescingExperimentConfig.html#/c:@S@IGListAdaptiveCoalescingExperimentConfig@FI@useMaxIntervalWhenViewNotVisible":{"name":"useMaxIntervalWhenViewNotVisible","abstract":"\u003cp\u003eCoalece using \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbStructs/IGListAdaptiveCoalescingExperimentConfig.html#/c:@S@IGListAdaptiveCoalescingExperimentConfig@FI@maxInterval\"\u003emaxInterval\u003c/a\u003e\u003c/code\u003e if view is not visible according to \u003ccode\u003eIGListViewVisibilityTracker\u003c/code\u003e\u003c/p\u003e","parent_name":"IGListAdaptiveCoalescingExperimentConfig"},"Structs/IGListAdaptiveDiffingExperimentConfig.html#/c:@S@IGListAdaptiveDiffingExperimentConfig@FI@enabled":{"name":"enabled","abstract":"\u003cp\u003eEnabled experimental code path. This needs to be enabled for the other properties to take effect.\u003c/p\u003e","parent_name":"IGListAdaptiveDiffingExperimentConfig"},"Structs/IGListAdaptiveDiffingExperimentConfig.html#/c:@S@IGListAdaptiveDiffingExperimentConfig@FI@higherQOSEnabled":{"name":"higherQOSEnabled","abstract":"\u003cp\u003eEnable higher background thread priority\u003c/p\u003e","parent_name":"IGListAdaptiveDiffingExperimentConfig"},"Structs/IGListAdaptiveDiffingExperimentConfig.html#/c:@S@IGListAdaptiveDiffingExperimentConfig@FI@maxItemCountToRunOnMain":{"name":"maxItemCountToRunOnMain","abstract":"\u003cp\u003eIf both item counts are under this number, we\u0026rsquo;ll run the diffing on the main thread.\u003c/p\u003e","parent_name":"IGListAdaptiveDiffingExperimentConfig"},"Structs/IGListAdaptiveDiffingExperimentConfig.html#/c:@S@IGListAdaptiveDiffingExperimentConfig@FI@lowerPriorityWhenViewNotVisible":{"name":"lowerPriorityWhenViewNotVisible","abstract":"\u003cp\u003eLower QOS if view is not visible according to \u003ccode\u003eIGListViewVisibilityTracker\u003c/code\u003e\u003c/p\u003e","parent_name":"IGListAdaptiveDiffingExperimentConfig"},"Structs/IGListAdaptiveDiffingExperimentConfig.html":{"name":"IGListAdaptiveDiffingExperimentConfig","abstract":"\u003cp\u003eCustomize how diffing is performed\u003c/p\u003e"},"Structs/IGListAdaptiveCoalescingExperimentConfig.html":{"name":"IGListAdaptiveCoalescingExperimentConfig","abstract":"\u003cp\u003eCustomize how coalescing works to speed up some updates\u003c/p\u003e"},"Structs/IGListCollectionScrollingTraits.html":{"name":"IGListCollectionScrollingTraits","abstract":"\u003cp\u003eThe current scrolling traits of the underlying collection view."},"Functions.html#/c:@F@IGListDiff":{"name":"IGListDiff","abstract":"\u003cp\u003eCreates a diff using indexes between two collections.\u003c/p\u003e"},"Functions.html#/c:@F@IGListDiffPaths":{"name":"IGListDiffPaths","abstract":"\u003cp\u003eCreates a diff using index paths between two collections.\u003c/p\u003e"},"Functions.html#/c:IGListExperiments.h@F@IGListExperimentEnabled":{"name":"IGListExperimentEnabled","abstract":"\u003cp\u003eCheck if an experiment is enabled in a bitmask.\u003c/p\u003e"},"Type%20Definitions/IGListCollectionScrollingTraits/IGListCollectionScrollingTraits.html#/c:@S@IGListCollectionScrollingTraits@FI@isTracking":{"name":"isTracking","abstract":"\u003cp\u003ereturns YES if user has touched. may not yet have started dragging.\u003c/p\u003e","parent_name":"IGListCollectionScrollingTraits"},"Type%20Definitions/IGListCollectionScrollingTraits/IGListCollectionScrollingTraits.html#/c:@S@IGListCollectionScrollingTraits@FI@isDragging":{"name":"isDragging","abstract":"\u003cp\u003ereturns YES if user has started scrolling. this may require some time and or distance to move to initiate dragging\u003c/p\u003e","parent_name":"IGListCollectionScrollingTraits"},"Type%20Definitions/IGListCollectionScrollingTraits/IGListCollectionScrollingTraits.html#/c:@S@IGListCollectionScrollingTraits@FI@isDecelerating":{"name":"isDecelerating","abstract":"\u003cp\u003ereturns YES if user isn\u0026rsquo;t dragging (touch up) but scroll view is still moving.\u003c/p\u003e","parent_name":"IGListCollectionScrollingTraits"},"Type%20Definitions/IGListCollectionScrollingTraits/IGListCollectionScrollingTraits.html":{"name":"IGListCollectionScrollingTraits","abstract":"\u003cp\u003eThe current scrolling traits of the underlying collection view.","parent_name":"IGListCollectionScrollingTraits"},"Type%20Definitions/IGListAdaptiveCoalescingExperimentConfig/IGListAdaptiveCoalescingExperimentConfig.html#/c:@S@IGListAdaptiveCoalescingExperimentConfig@FI@enabled":{"name":"enabled","abstract":"\u003cp\u003eEnable adaptive coalescing, where we try to mininimize the update delay\u003c/p\u003e","parent_name":"IGListAdaptiveCoalescingExperimentConfig"},"Type%20Definitions/IGListAdaptiveCoalescingExperimentConfig/IGListAdaptiveCoalescingExperimentConfig.html#/c:@S@IGListAdaptiveCoalescingExperimentConfig@FI@minInterval":{"name":"minInterval","abstract":"\u003cp\u003eStart coalescing if the last update was within this interval\u003c/p\u003e","parent_name":"IGListAdaptiveCoalescingExperimentConfig"},"Type%20Definitions/IGListAdaptiveCoalescingExperimentConfig/IGListAdaptiveCoalescingExperimentConfig.html#/c:@S@IGListAdaptiveCoalescingExperimentConfig@FI@intervalIncrement":{"name":"intervalIncrement","abstract":"\u003cp\u003eIf we need to coalesce, increase the interval by this much for next time.\u003c/p\u003e","parent_name":"IGListAdaptiveCoalescingExperimentConfig"},"Type%20Definitions/IGListAdaptiveCoalescingExperimentConfig/IGListAdaptiveCoalescingExperimentConfig.html#/c:@S@IGListAdaptiveCoalescingExperimentConfig@FI@maxInterval":{"name":"maxInterval","abstract":"\u003cp\u003eThis is the maximum coalesce interval, so the slowest and update can wait.\u003c/p\u003e","parent_name":"IGListAdaptiveCoalescingExperimentConfig"},"Type%20Definitions/IGListAdaptiveCoalescingExperimentConfig/IGListAdaptiveCoalescingExperimentConfig.html#/c:@S@IGListAdaptiveCoalescingExperimentConfig@FI@useMaxIntervalWhenViewNotVisible":{"name":"useMaxIntervalWhenViewNotVisible","abstract":"\u003cp\u003eCoalece using \u003ccode\u003emaxInterval\u003c/code\u003e if view is not visible according to \u003ccode\u003eIGListViewVisibilityTracker\u003c/code\u003e\u003c/p\u003e","parent_name":"IGListAdaptiveCoalescingExperimentConfig"},"Type%20Definitions/IGListAdaptiveCoalescingExperimentConfig/IGListAdaptiveCoalescingExperimentConfig.html":{"name":"IGListAdaptiveCoalescingExperimentConfig","abstract":"\u003cp\u003eCustomize how coalescing works to speed up some updates\u003c/p\u003e","parent_name":"IGListAdaptiveCoalescingExperimentConfig"},"Type%20Definitions/IGListAdaptiveDiffingExperimentConfig/IGListAdaptiveDiffingExperimentConfig.html#/c:@S@IGListAdaptiveDiffingExperimentConfig@FI@enabled":{"name":"enabled","abstract":"\u003cp\u003eEnabled experimental code path. This needs to be enabled for the other properties to take effect.\u003c/p\u003e","parent_name":"IGListAdaptiveDiffingExperimentConfig"},"Type%20Definitions/IGListAdaptiveDiffingExperimentConfig/IGListAdaptiveDiffingExperimentConfig.html#/c:@S@IGListAdaptiveDiffingExperimentConfig@FI@higherQOSEnabled":{"name":"higherQOSEnabled","abstract":"\u003cp\u003eEnable higher background thread priority\u003c/p\u003e","parent_name":"IGListAdaptiveDiffingExperimentConfig"},"Type%20Definitions/IGListAdaptiveDiffingExperimentConfig/IGListAdaptiveDiffingExperimentConfig.html#/c:@S@IGListAdaptiveDiffingExperimentConfig@FI@maxItemCountToRunOnMain":{"name":"maxItemCountToRunOnMain","abstract":"\u003cp\u003eIf both item counts are under this number, we\u0026rsquo;ll run the diffing on the main thread.\u003c/p\u003e","parent_name":"IGListAdaptiveDiffingExperimentConfig"},"Type%20Definitions/IGListAdaptiveDiffingExperimentConfig/IGListAdaptiveDiffingExperimentConfig.html#/c:@S@IGListAdaptiveDiffingExperimentConfig@FI@lowerPriorityWhenViewNotVisible":{"name":"lowerPriorityWhenViewNotVisible","abstract":"\u003cp\u003eLower QOS if view is not visible according to \u003ccode\u003eIGListViewVisibilityTracker\u003c/code\u003e\u003c/p\u003e","parent_name":"IGListAdaptiveDiffingExperimentConfig"},"Type%20Definitions/IGListAdaptiveDiffingExperimentConfig/IGListAdaptiveDiffingExperimentConfig.html":{"name":"IGListAdaptiveDiffingExperimentConfig","abstract":"\u003cp\u003eCustomize how diffing is performed\u003c/p\u003e","parent_name":"IGListAdaptiveDiffingExperimentConfig"},"Type%20Definitions/IGListAdaptiveDiffingExperimentConfig.html":{"name":"IGListAdaptiveDiffingExperimentConfig","abstract":"\u003cp\u003eCustomize how diffing is performed\u003c/p\u003e"},"Type%20Definitions/IGListAdaptiveCoalescingExperimentConfig.html":{"name":"IGListAdaptiveCoalescingExperimentConfig","abstract":"\u003cp\u003eCustomize how coalescing works to speed up some updates\u003c/p\u003e"},"Type%20Definitions.html#/c:IGListAdapter.h@T@IGListUpdaterCompletion":{"name":"IGListUpdaterCompletion","abstract":"\u003cp\u003eA block to execute when the list updates are completed.\u003c/p\u003e"},"Type%20Definitions/IGListCollectionScrollingTraits.html":{"name":"IGListCollectionScrollingTraits","abstract":"\u003cp\u003eThe current scrolling traits of the underlying collection view."},"Type%20Definitions.html#/c:IGListSingleSectionController.h@T@IGListSingleSectionCellConfigureBlock":{"name":"IGListSingleSectionCellConfigureBlock","abstract":"\u003cp\u003eA block used to configure cells.\u003c/p\u003e"},"Type%20Definitions.html#/c:IGListSingleSectionController.h@T@IGListSingleSectionCellSizeBlock":{"name":"IGListSingleSectionCellSizeBlock","abstract":"\u003cp\u003eA block that returns the size for the cell given the collection context.\u003c/p\u003e"},"Type%20Definitions.html#/c:IGListUpdatingDelegate.h@T@IGListUpdatingCompletion":{"name":"IGListUpdatingCompletion","abstract":"\u003cp\u003eA completion block to execute when updates are finished.\u003c/p\u003e"},"Type%20Definitions.html#/c:IGListUpdatingDelegate.h@T@IGListObjectTransitionBlock":{"name":"IGListObjectTransitionBlock","abstract":"\u003cp\u003eA block to be called when the adapter applies changes to the collection view.\u003c/p\u003e"},"Type%20Definitions.html#/c:IGListUpdatingDelegate.h@T@IGListItemUpdateBlock":{"name":"IGListItemUpdateBlock","abstract":"\u003cp\u003eA block that contains all of the updates.\u003c/p\u003e"},"Type%20Definitions.html#/c:IGListUpdatingDelegate.h@T@IGListReloadUpdateBlock":{"name":"IGListReloadUpdateBlock","abstract":"\u003cp\u003eA block to be called when an adapter reloads the collection view.\u003c/p\u003e"},"Type%20Definitions.html#/c:IGListUpdatingDelegate.h@T@IGListToObjectBlock":{"name":"IGListToObjectBlock","abstract":"\u003cp\u003eA block that returns an array of objects to transition to.\u003c/p\u003e"},"Type%20Definitions.html#/c:IGListUpdatingDelegate.h@T@IGListCollectionViewBlock":{"name":"IGListCollectionViewBlock","abstract":"\u003cp\u003eA block that returns a collection view to perform updates on.\u003c/p\u003e"},"Type%20Definitions.html#/c:IGListUpdatingDelegate.h@T@IGListDataSourceChangeBlock":{"name":"IGListDataSourceChangeBlock","abstract":"\u003cp\u003eA block that applies a \u003ccode\u003eUICollectionView\u003c/code\u003e dataSource change\u003c/p\u003e"},"Type%20Definitions.html#/c:IGListUpdatingDelegate.h@T@IGListTransitionDataBlock":{"name":"IGListTransitionDataBlock","abstract":"\u003cp\u003eA block that returns the \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/IGListTransitionData.html\"\u003eIGListTransitionData\u003c/a\u003e\u003c/code\u003e needed before an update.\u003c/p\u003e"},"Type%20Definitions.html#/c:IGListUpdatingDelegate.h@T@IGListTransitionDataApplyBlock":{"name":"IGListTransitionDataApplyBlock","abstract":"\u003cp\u003eA block to be called when the adapter applies changes to the collection view.\u003c/p\u003e"},"Protocols/IGListWorkingRangeDelegate.html#/c:objc(pl)IGListWorkingRangeDelegate(im)listAdapter:sectionControllerWillEnterWorkingRange:":{"name":"-listAdapter:sectionControllerWillEnterWorkingRange:","abstract":"\u003cp\u003eNotifies the delegate that an section controller will enter the working range.\u003c/p\u003e","parent_name":"IGListWorkingRangeDelegate"},"Protocols/IGListWorkingRangeDelegate.html#/c:objc(pl)IGListWorkingRangeDelegate(im)listAdapter:sectionControllerDidExitWorkingRange:":{"name":"-listAdapter:sectionControllerDidExitWorkingRange:","abstract":"\u003cp\u003eNotifies the delegate that an section controller exited the working range.\u003c/p\u003e","parent_name":"IGListWorkingRangeDelegate"},"Protocols/IGListUpdatingDelegate.html#/c:objc(pl)IGListUpdatingDelegate(im)objectLookupPointerFunctions":{"name":"-objectLookupPointerFunctions","abstract":"\u003cp\u003eAsks the delegate for the pointer functions for looking up an object in a collection.\u003c/p\u003e","parent_name":"IGListUpdatingDelegate"},"Protocols/IGListUpdatingDelegate.html#/c:objc(pl)IGListUpdatingDelegate(im)performUpdateWithCollectionViewBlock:animated:sectionDataBlock:applySectionDataBlock:completion:":{"name":"-performUpdateWithCollectionViewBlock:animated:sectionDataBlock:applySectionDataBlock:completion:","abstract":"\u003cp\u003ePerform a \u003cstrong\u003esection\u003c/strong\u003e update from an old array of objects to a new one.\u003c/p\u003e","parent_name":"IGListUpdatingDelegate"},"Protocols/IGListUpdatingDelegate.html#/c:objc(pl)IGListUpdatingDelegate(im)performUpdateWithCollectionViewBlock:animated:itemUpdates:completion:":{"name":"-performUpdateWithCollectionViewBlock:animated:itemUpdates:completion:","abstract":"\u003cp\u003ePerform an \u003cstrong\u003eitem\u003c/strong\u003e update block in the collection view.\u003c/p\u003e","parent_name":"IGListUpdatingDelegate"},"Protocols/IGListUpdatingDelegate.html#/c:objc(pl)IGListUpdatingDelegate(im)performDataSourceChange:":{"name":"-performDataSourceChange:","abstract":"\u003cp\u003ePerform a \u003ccode\u003e[UICollectionView setDataSource:...]\u003c/code\u003e swap within this block. It gives the updater the chance to cancel or","parent_name":"IGListUpdatingDelegate"},"Protocols/IGListUpdatingDelegate.html#/c:objc(pl)IGListUpdatingDelegate(im)reloadDataWithCollectionViewBlock:reloadUpdateBlock:completion:":{"name":"-reloadDataWithCollectionViewBlock:reloadUpdateBlock:completion:","abstract":"\u003cp\u003eCompletely reload data in the collection.\u003c/p\u003e","parent_name":"IGListUpdatingDelegate"},"Protocols/IGListUpdatingDelegate.html#/c:objc(pl)IGListUpdatingDelegate(im)insertItemsIntoCollectionView:indexPaths:":{"name":"-insertItemsIntoCollectionView:indexPaths:","abstract":"\u003cp\u003eTells the delegate to perform item inserts at the given index paths.\u003c/p\u003e","parent_name":"IGListUpdatingDelegate"},"Protocols/IGListUpdatingDelegate.html#/c:objc(pl)IGListUpdatingDelegate(im)deleteItemsFromCollectionView:indexPaths:":{"name":"-deleteItemsFromCollectionView:indexPaths:","abstract":"\u003cp\u003eTells the delegate to perform item deletes at the given index paths.\u003c/p\u003e","parent_name":"IGListUpdatingDelegate"},"Protocols/IGListUpdatingDelegate.html#/c:objc(pl)IGListUpdatingDelegate(im)moveItemInCollectionView:fromIndexPath:toIndexPath:":{"name":"-moveItemInCollectionView:fromIndexPath:toIndexPath:","abstract":"\u003cp\u003eTells the delegate to move an item from and to given index paths.\u003c/p\u003e","parent_name":"IGListUpdatingDelegate"},"Protocols/IGListUpdatingDelegate.html#/c:objc(pl)IGListUpdatingDelegate(im)reloadItemInCollectionView:fromIndexPath:toIndexPath:":{"name":"-reloadItemInCollectionView:fromIndexPath:toIndexPath:","abstract":"\u003cp\u003eTells the delegate to reload an item from and to given index paths.\u003c/p\u003e","parent_name":"IGListUpdatingDelegate"},"Protocols/IGListUpdatingDelegate.html#/c:objc(pl)IGListUpdatingDelegate(im)moveSectionInCollectionView:fromIndex:toIndex:":{"name":"-moveSectionInCollectionView:fromIndex:toIndex:","abstract":"\u003cp\u003eTells the delegate to move a section from and to given indexes.\u003c/p\u003e","parent_name":"IGListUpdatingDelegate"},"Protocols/IGListUpdatingDelegate.html#/c:objc(pl)IGListUpdatingDelegate(im)reloadCollectionView:sections:":{"name":"-reloadCollectionView:sections:","abstract":"\u003cp\u003eCompletely reload each section in the collection view.\u003c/p\u003e","parent_name":"IGListUpdatingDelegate"},"Protocols/IGListUpdatingDelegate.html#/c:objc(pl)IGListUpdatingDelegate(im)isInDataUpdateBlock":{"name":"-isInDataUpdateBlock","abstract":"\u003cp\u003eTrue if the updater is currently updating the source of truth, like executing applySectionDataBlock and","parent_name":"IGListUpdatingDelegate"},"Protocols/IGListUpdatingDelegate.html#/c:objc(pl)IGListUpdatingDelegate(im)willCrashWithCollectionView:sectionControllerClass:":{"name":"-willCrashWithCollectionView:sectionControllerClass:","abstract":"\u003cp\u003eCalled when the updater detects an imminent crash, such as when a section controller returns a nil cell.","parent_name":"IGListUpdatingDelegate"},"Protocols/IGListTransitionDelegate.html#/c:objc(pl)IGListTransitionDelegate(im)listAdapter:customizedInitialLayoutAttributes:sectionController:atIndex:":{"name":"-listAdapter:customizedInitialLayoutAttributes:sectionController:atIndex:","abstract":"\u003cp\u003eAsks the delegate to customize and return the starting layout information for an item being inserted into the collection view.\u003c/p\u003e","parent_name":"IGListTransitionDelegate"},"Protocols/IGListTransitionDelegate.html#/c:objc(pl)IGListTransitionDelegate(im)listAdapter:customizedFinalLayoutAttributes:sectionController:atIndex:":{"name":"-listAdapter:customizedFinalLayoutAttributes:sectionController:atIndex:","abstract":"\u003cp\u003eAsks the delegate to customize and return the final layout information for an item that is about to be removed from the collection view.\u003c/p\u003e","parent_name":"IGListTransitionDelegate"},"Protocols/IGListSupplementaryViewSource.html#/c:objc(pl)IGListSupplementaryViewSource(im)supportedElementKinds":{"name":"-supportedElementKinds","abstract":"\u003cp\u003eAsks the SupplementaryViewSource for an array of supported element kinds.\u003c/p\u003e","parent_name":"IGListSupplementaryViewSource"},"Protocols/IGListSupplementaryViewSource.html#/c:objc(pl)IGListSupplementaryViewSource(im)viewForSupplementaryElementOfKind:atIndex:":{"name":"-viewForSupplementaryElementOfKind:atIndex:","abstract":"\u003cp\u003eAsks the SupplementaryViewSource for a configured supplementary view for the specified kind and index.\u003c/p\u003e","parent_name":"IGListSupplementaryViewSource"},"Protocols/IGListSupplementaryViewSource.html#/c:objc(pl)IGListSupplementaryViewSource(im)sizeForSupplementaryViewOfKind:atIndex:":{"name":"-sizeForSupplementaryViewOfKind:atIndex:","abstract":"\u003cp\u003eAsks the SupplementaryViewSource for the size of a supplementary view for the given kind and index path.\u003c/p\u003e","parent_name":"IGListSupplementaryViewSource"},"Protocols/IGListSingleSectionControllerDelegate.html#/c:objc(pl)IGListSingleSectionControllerDelegate(im)didSelectSectionController:withObject:":{"name":"-didSelectSectionController:withObject:","abstract":"\u003cp\u003eTells the delegate that the section controller was selected.\u003c/p\u003e","parent_name":"IGListSingleSectionControllerDelegate"},"Protocols/IGListSingleSectionControllerDelegate.html#/c:objc(pl)IGListSingleSectionControllerDelegate(im)didDeselectSectionController:withObject:":{"name":"-didDeselectSectionController:withObject:","abstract":"\u003cp\u003eTells the delegate that the section controller was deselected.\u003c/p\u003e","parent_name":"IGListSingleSectionControllerDelegate"},"Protocols/IGListScrollDelegate.html#/c:objc(pl)IGListScrollDelegate(im)listAdapter:didScrollSectionController:":{"name":"-listAdapter:didScrollSectionController:","abstract":"\u003cp\u003eTells the delegate that the section controller was scrolled on screen.\u003c/p\u003e","parent_name":"IGListScrollDelegate"},"Protocols/IGListScrollDelegate.html#/c:objc(pl)IGListScrollDelegate(im)listAdapter:willBeginDraggingSectionController:":{"name":"-listAdapter:willBeginDraggingSectionController:","abstract":"\u003cp\u003eTells the delegate that the section controller will be dragged on screen.\u003c/p\u003e","parent_name":"IGListScrollDelegate"},"Protocols/IGListScrollDelegate.html#/c:objc(pl)IGListScrollDelegate(im)listAdapter:didEndDraggingSectionController:willDecelerate:":{"name":"-listAdapter:didEndDraggingSectionController:willDecelerate:","abstract":"\u003cp\u003eTells the delegate that the section controller did end dragging on screen.\u003c/p\u003e","parent_name":"IGListScrollDelegate"},"Protocols/IGListScrollDelegate.html#/c:objc(pl)IGListScrollDelegate(im)listAdapter:didEndDeceleratingSectionController:":{"name":"-listAdapter:didEndDeceleratingSectionController:","abstract":"\u003cp\u003eTells the delegate that the section controller did end decelerating on screen.\u003c/p\u003e","parent_name":"IGListScrollDelegate"},"Protocols/IGListDisplayDelegate.html#/c:objc(pl)IGListDisplayDelegate(im)listAdapter:willDisplaySectionController:":{"name":"-listAdapter:willDisplaySectionController:","abstract":"\u003cp\u003eTells the delegate that the specified section controller is about to be displayed.\u003c/p\u003e","parent_name":"IGListDisplayDelegate"},"Protocols/IGListDisplayDelegate.html#/c:objc(pl)IGListDisplayDelegate(im)listAdapter:didEndDisplayingSectionController:":{"name":"-listAdapter:didEndDisplayingSectionController:","abstract":"\u003cp\u003eTells the delegate that the specified section controller is no longer being displayed.\u003c/p\u003e","parent_name":"IGListDisplayDelegate"},"Protocols/IGListDisplayDelegate.html#/c:objc(pl)IGListDisplayDelegate(im)listAdapter:willDisplaySectionController:cell:atIndex:":{"name":"-listAdapter:willDisplaySectionController:cell:atIndex:","abstract":"\u003cp\u003eTells the delegate that a cell in the specified list is about to be displayed.\u003c/p\u003e","parent_name":"IGListDisplayDelegate"},"Protocols/IGListDisplayDelegate.html#/c:objc(pl)IGListDisplayDelegate(im)listAdapter:didEndDisplayingSectionController:cell:atIndex:":{"name":"-listAdapter:didEndDisplayingSectionController:cell:atIndex:","abstract":"\u003cp\u003eTells the delegate that a cell in the specified list is no longer being displayed.\u003c/p\u003e","parent_name":"IGListDisplayDelegate"},"Protocols/IGListCollectionViewLayoutCompatible.html#/c:objc(pl)IGListCollectionViewLayoutCompatible(im)didModifySection:":{"name":"-didModifySection:","abstract":"\u003cp\u003eCalled to notify the layout that a specific section was modified before invalidation. This can be used to optimize","parent_name":"IGListCollectionViewLayoutCompatible"},"Protocols/IGListCollectionViewDelegateLayout.html#/c:objc(pl)IGListCollectionViewDelegateLayout(im)collectionView:layout:customizedInitialLayoutAttributes:atIndexPath:":{"name":"-collectionView:layout:customizedInitialLayoutAttributes:atIndexPath:","abstract":"\u003cp\u003eAsks the delegate to customize and return the starting layout information for an item being inserted into the collection view.\u003c/p\u003e","parent_name":"IGListCollectionViewDelegateLayout"},"Protocols/IGListCollectionViewDelegateLayout.html#/c:objc(pl)IGListCollectionViewDelegateLayout(im)collectionView:layout:customizedFinalLayoutAttributes:atIndexPath:":{"name":"-collectionView:layout:customizedFinalLayoutAttributes:atIndexPath:","abstract":"\u003cp\u003eAsks the delegate to customize and return the final layout information for an item that is about to be removed from the collection view.\u003c/p\u003e","parent_name":"IGListCollectionViewDelegateLayout"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(py)containerSize":{"name":"containerSize","abstract":"\u003cp\u003eThe size of the collection view. You can use this for sizing cells.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(py)containerInset":{"name":"containerInset","abstract":"\u003cp\u003eThe content insets of the collection view. You can use this for sizing cells.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(py)adjustedContainerInset":{"name":"adjustedContainerInset","abstract":"\u003cp\u003eThe adjusted content insets of the collection view. Equivalent to containerInset under iOS 11.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(py)insetContainerSize":{"name":"insetContainerSize","abstract":"\u003cp\u003eThe size of the collection view with content insets applied.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(py)containerContentOffset":{"name":"containerContentOffset","abstract":"\u003cp\u003eThe content offset of the collection view.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(py)traitCollection":{"name":"traitCollection","abstract":"\u003cp\u003eThe trait collection of the collection view.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(py)scrollingTraits":{"name":"scrollingTraits","abstract":"\u003cp\u003eThe current scrolling traits of the underlying collection view.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(py)experiments":{"name":"experiments","abstract":"\u003cp\u003eA bitmask of experiments to conduct on the section controller.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(im)containerSizeForSectionController:":{"name":"-containerSizeForSectionController:","abstract":"\u003cp\u003eReturns size of the collection view relative to the section controller.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(im)indexForCell:sectionController:":{"name":"-indexForCell:sectionController:","abstract":"\u003cp\u003eReturns the index of the specified cell in the collection relative to the section controller.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(im)cellForItemAtIndex:sectionController:":{"name":"-cellForItemAtIndex:sectionController:","abstract":"\u003cp\u003eReturns the cell in the collection at the specified index for the section controller.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(im)viewForSupplementaryElementOfKind:atIndex:sectionController:":{"name":"-viewForSupplementaryElementOfKind:atIndex:sectionController:","abstract":"\u003cp\u003eReturns the supplementary view in the collection at the specified index for the section controller.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(im)fullyVisibleCellsForSectionController:":{"name":"-fullyVisibleCellsForSectionController:","abstract":"\u003cp\u003eReturns the fully visible cells for the given section controller.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(im)visibleCellsForSectionController:":{"name":"-visibleCellsForSectionController:","abstract":"\u003cp\u003eReturns the visible cells for the given section controller.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(im)visibleIndexPathsForSectionController:":{"name":"-visibleIndexPathsForSectionController:","abstract":"\u003cp\u003eReturns the visible paths for the given section controller.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(im)deselectItemAtIndex:sectionController:animated:":{"name":"-deselectItemAtIndex:sectionController:animated:","abstract":"\u003cp\u003eDeselects a cell in the collection.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(im)selectItemAtIndex:sectionController:animated:scrollPosition:":{"name":"-selectItemAtIndex:sectionController:animated:scrollPosition:","abstract":"\u003cp\u003eSelects a cell in the collection.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(im)dequeueReusableCellOfClass:withReuseIdentifier:forSectionController:atIndex:":{"name":"-dequeueReusableCellOfClass:withReuseIdentifier:forSectionController:atIndex:","abstract":"\u003cp\u003eDequeues a cell from the collection view reuse pool.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(im)dequeueReusableCellOfClass:forSectionController:atIndex:":{"name":"-dequeueReusableCellOfClass:forSectionController:atIndex:","abstract":"\u003cp\u003eDequeues a cell from the collection view reuse pool.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(im)dequeueReusableCellWithNibName:bundle:forSectionController:atIndex:":{"name":"-dequeueReusableCellWithNibName:bundle:forSectionController:atIndex:","abstract":"\u003cp\u003eDequeues a cell from the collection view reuse pool.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(im)dequeueReusableCellFromStoryboardWithIdentifier:forSectionController:atIndex:":{"name":"-dequeueReusableCellFromStoryboardWithIdentifier:forSectionController:atIndex:","abstract":"\u003cp\u003eDequeues a storyboard prototype cell from the collection view reuse pool.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(im)dequeueReusableSupplementaryViewOfKind:forSectionController:class:atIndex:":{"name":"-dequeueReusableSupplementaryViewOfKind:forSectionController:class:atIndex:","abstract":"\u003cp\u003eDequeues a supplementary view from the collection view reuse pool.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(im)dequeueReusableSupplementaryViewFromStoryboardOfKind:withIdentifier:forSectionController:atIndex:":{"name":"-dequeueReusableSupplementaryViewFromStoryboardOfKind:withIdentifier:forSectionController:atIndex:","abstract":"\u003cp\u003eDequeues a supplementary view from the collection view reuse pool.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(im)dequeueReusableSupplementaryViewOfKind:forSectionController:nibName:bundle:atIndex:":{"name":"-dequeueReusableSupplementaryViewOfKind:forSectionController:nibName:bundle:atIndex:","abstract":"\u003cp\u003eDequeues a supplementary view from the collection view reuse pool.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(im)invalidateLayoutForSectionController:completion:":{"name":"-invalidateLayoutForSectionController:completion:","abstract":"\u003cp\u003eInvalidate the backing \u003ccode\u003eUICollectionViewLayout\u003c/code\u003e for all items in the section controller.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(im)layoutAttributesForItemAtIndex:sectionController:":{"name":"-layoutAttributesForItemAtIndex:sectionController:","abstract":"\u003cp\u003eReturns the layout attributes for the item at the specified index in the section controller.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(im)performBatchAnimated:updates:completion:":{"name":"-performBatchAnimated:updates:completion:","abstract":"\u003cp\u003eBatches and performs many cell-level updates in a single transaction.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(im)scrollToSectionController:atIndex:scrollPosition:animated:":{"name":"-scrollToSectionController:atIndex:scrollPosition:animated:","abstract":"\u003cp\u003eScrolls to the specified section controller in the list.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(im)indexPathForItemAtPoint:":{"name":"-indexPathForItemAtPoint:","abstract":"\u003cp\u003eReturns the index path of the item at the specified point in the collection view.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(im)convertPoint:fromView:":{"name":"-convertPoint:fromView:","abstract":"\u003cp\u003eConverts a point from the coordinate system of a given view to that of the collection view.\u003c/p\u003e","parent_name":"IGListCollectionContext"},"Protocols/IGListBindingSectionControllerSelectionDelegate.html#/c:objc(pl)IGListBindingSectionControllerSelectionDelegate(im)sectionController:didSelectItemAtIndex:viewModel:":{"name":"-sectionController:didSelectItemAtIndex:viewModel:","abstract":"\u003cp\u003eTells the delegate that a cell at a given index was selected.\u003c/p\u003e","parent_name":"IGListBindingSectionControllerSelectionDelegate"},"Protocols/IGListBindingSectionControllerSelectionDelegate.html#/c:objc(pl)IGListBindingSectionControllerSelectionDelegate(im)sectionController:didDeselectItemAtIndex:viewModel:":{"name":"-sectionController:didDeselectItemAtIndex:viewModel:","abstract":"\u003cp\u003eTells the delegate that a cell at a given index was deselected.\u003c/p\u003e","parent_name":"IGListBindingSectionControllerSelectionDelegate"},"Protocols/IGListBindingSectionControllerSelectionDelegate.html#/c:objc(pl)IGListBindingSectionControllerSelectionDelegate(im)sectionController:didHighlightItemAtIndex:viewModel:":{"name":"-sectionController:didHighlightItemAtIndex:viewModel:","abstract":"\u003cp\u003eTells the delegate that a cell at a given index was highlighted.\u003c/p\u003e","parent_name":"IGListBindingSectionControllerSelectionDelegate"},"Protocols/IGListBindingSectionControllerSelectionDelegate.html#/c:objc(pl)IGListBindingSectionControllerSelectionDelegate(im)sectionController:didUnhighlightItemAtIndex:viewModel:":{"name":"-sectionController:didUnhighlightItemAtIndex:viewModel:","abstract":"\u003cp\u003eTells the delegate that a cell at a given index was unhighlighted.\u003c/p\u003e","parent_name":"IGListBindingSectionControllerSelectionDelegate"},"Protocols/IGListBindingSectionControllerSelectionDelegate.html#/c:objc(pl)IGListBindingSectionControllerSelectionDelegate(im)sectionController:contextMenuConfigurationForItemAtIndex:point:viewModel:":{"name":"-sectionController:contextMenuConfigurationForItemAtIndex:point:viewModel:","abstract":"\u003cp\u003eTells the delegate that a cell has requested a menu configuration.\u003c/p\u003e","parent_name":"IGListBindingSectionControllerSelectionDelegate"},"Protocols/IGListBindingSectionControllerDataSource.html#/c:objc(pl)IGListBindingSectionControllerDataSource(im)sectionController:viewModelsForObject:":{"name":"-sectionController:viewModelsForObject:","abstract":"\u003cp\u003eCreate an array of view models given a top-level object.\u003c/p\u003e","parent_name":"IGListBindingSectionControllerDataSource"},"Protocols/IGListBindingSectionControllerDataSource.html#/c:objc(pl)IGListBindingSectionControllerDataSource(im)sectionController:cellForViewModel:atIndex:":{"name":"-sectionController:cellForViewModel:atIndex:","abstract":"\u003cp\u003eReturn a dequeued cell for a given view model.\u003c/p\u003e","parent_name":"IGListBindingSectionControllerDataSource"},"Protocols/IGListBindingSectionControllerDataSource.html#/c:objc(pl)IGListBindingSectionControllerDataSource(im)sectionController:sizeForViewModel:atIndex:":{"name":"-sectionController:sizeForViewModel:atIndex:","abstract":"\u003cp\u003eReturn a cell size for a given view model.\u003c/p\u003e","parent_name":"IGListBindingSectionControllerDataSource"},"Protocols/IGListBindable.html#/c:objc(pl)IGListBindable(im)bindViewModel:":{"name":"-bindViewModel:","abstract":"\u003cp\u003eTells the cell to configure itself with the given view model.\u003c/p\u003e","parent_name":"IGListBindable"},"Protocols/IGListBatchContext.html#/c:objc(pl)IGListBatchContext(im)reloadInSectionController:atIndexes:":{"name":"-reloadInSectionController:atIndexes:","abstract":"\u003cp\u003eReloads cells in the section controller.\u003c/p\u003e","parent_name":"IGListBatchContext"},"Protocols/IGListBatchContext.html#/c:objc(pl)IGListBatchContext(im)insertInSectionController:atIndexes:":{"name":"-insertInSectionController:atIndexes:","abstract":"\u003cp\u003eInserts cells in the list.\u003c/p\u003e","parent_name":"IGListBatchContext"},"Protocols/IGListBatchContext.html#/c:objc(pl)IGListBatchContext(im)deleteInSectionController:atIndexes:":{"name":"-deleteInSectionController:atIndexes:","abstract":"\u003cp\u003eDeletes cells in the list.\u003c/p\u003e","parent_name":"IGListBatchContext"},"Protocols/IGListBatchContext.html#/c:objc(pl)IGListBatchContext(im)invalidateLayoutInSectionController:atIndexes:":{"name":"-invalidateLayoutInSectionController:atIndexes:","abstract":"\u003cp\u003eInvalidates layouts of cells at specific in the section controller.\u003c/p\u003e","parent_name":"IGListBatchContext"},"Protocols/IGListBatchContext.html#/c:objc(pl)IGListBatchContext(im)moveInSectionController:fromIndex:toIndex:":{"name":"-moveInSectionController:fromIndex:toIndex:","abstract":"\u003cp\u003eMoves a cell from one index to another within the section controller.\u003c/p\u003e","parent_name":"IGListBatchContext"},"Protocols/IGListBatchContext.html#/c:objc(pl)IGListBatchContext(im)reloadSectionController:":{"name":"-reloadSectionController:","abstract":"\u003cp\u003eReloads the entire section controller.\u003c/p\u003e","parent_name":"IGListBatchContext"},"Protocols/IGListBatchContext.html#/c:objc(pl)IGListBatchContext(im)moveSectionControllerInteractive:fromIndex:toIndex:":{"name":"-moveSectionControllerInteractive:fromIndex:toIndex:","abstract":"\u003cp\u003eMoves a section controller from one index to another during interactive reordering.\u003c/p\u003e","parent_name":"IGListBatchContext"},"Protocols/IGListBatchContext.html#/c:objc(pl)IGListBatchContext(im)moveInSectionControllerInteractive:fromIndex:toIndex:":{"name":"-moveInSectionControllerInteractive:fromIndex:toIndex:","abstract":"\u003cp\u003eMoves an object within a section controller from one index to another during interactive reordering.\u003c/p\u003e","parent_name":"IGListBatchContext"},"Protocols/IGListBatchContext.html#/c:objc(pl)IGListBatchContext(im)revertInvalidInteractiveMoveFromIndexPath:toIndexPath:":{"name":"-revertInvalidInteractiveMoveFromIndexPath:toIndexPath:","abstract":"\u003cp\u003eReverts an move from one indexPath to another during interactive reordering.\u003c/p\u003e","parent_name":"IGListBatchContext"},"Protocols/IGListAdapterUpdaterDelegate.html#/c:objc(pl)IGListAdapterUpdaterDelegate(im)listAdapterUpdater:willDiffFromObjects:toObjects:":{"name":"-listAdapterUpdater:willDiffFromObjects:toObjects:","abstract":"\u003cp\u003eNotifies the delegate that the updater is about to beging diffing.\u003c/p\u003e","parent_name":"IGListAdapterUpdaterDelegate"},"Protocols/IGListAdapterUpdaterDelegate.html#/c:objc(pl)IGListAdapterUpdaterDelegate(im)listAdapterUpdater:didDiffWithResults:onBackgroundThread:":{"name":"-listAdapterUpdater:didDiffWithResults:onBackgroundThread:","abstract":"\u003cp\u003eNotifies the delegate that the updater finished diffing.\u003c/p\u003e","parent_name":"IGListAdapterUpdaterDelegate"},"Protocols/IGListAdapterUpdaterDelegate.html#/c:objc(pl)IGListAdapterUpdaterDelegate(im)listAdapterUpdater:willPerformBatchUpdatesWithCollectionView:fromObjects:toObjects:listIndexSetResult:animated:":{"name":"-listAdapterUpdater:willPerformBatchUpdatesWithCollectionView:fromObjects:toObjects:listIndexSetResult:animated:","abstract":"\u003cp\u003eNotifies the delegate that the updater will call \u003ccode\u003e-[UICollectionView performBatchUpdates:completion:]\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListAdapterUpdaterDelegate"},"Protocols/IGListAdapterUpdaterDelegate.html#/c:objc(pl)IGListAdapterUpdaterDelegate(im)listAdapterUpdater:didPerformBatchUpdates:collectionView:":{"name":"-listAdapterUpdater:didPerformBatchUpdates:collectionView:","abstract":"\u003cp\u003eNotifies the delegate that the updater successfully finished \u003ccode\u003e-[UICollectionView performBatchUpdates:completion:]\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListAdapterUpdaterDelegate"},"Protocols/IGListAdapterUpdaterDelegate.html#/c:objc(pl)IGListAdapterUpdaterDelegate(im)listAdapterUpdater:willInsertIndexPaths:collectionView:":{"name":"-listAdapterUpdater:willInsertIndexPaths:collectionView:","abstract":"\u003cp\u003eNotifies the delegate that the updater will call \u003ccode\u003e-[UICollectionView insertItemsAtIndexPaths:]\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListAdapterUpdaterDelegate"},"Protocols/IGListAdapterUpdaterDelegate.html#/c:objc(pl)IGListAdapterUpdaterDelegate(im)listAdapterUpdater:willDeleteIndexPaths:collectionView:":{"name":"-listAdapterUpdater:willDeleteIndexPaths:collectionView:","abstract":"\u003cp\u003eNotifies the delegate that the updater will call \u003ccode\u003e-[UICollectionView deleteItemsAtIndexPaths:]\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListAdapterUpdaterDelegate"},"Protocols/IGListAdapterUpdaterDelegate.html#/c:objc(pl)IGListAdapterUpdaterDelegate(im)listAdapterUpdater:willMoveFromIndexPath:toIndexPath:collectionView:":{"name":"-listAdapterUpdater:willMoveFromIndexPath:toIndexPath:collectionView:","abstract":"\u003cp\u003eNotifies the delegate that the updater will call \u003ccode\u003e-[UICollectionView moveItemAtIndexPath:toIndexPath:]\u003c/code\u003e\u003c/p\u003e","parent_name":"IGListAdapterUpdaterDelegate"},"Protocols/IGListAdapterUpdaterDelegate.html#/c:objc(pl)IGListAdapterUpdaterDelegate(im)listAdapterUpdater:willReloadIndexPaths:collectionView:":{"name":"-listAdapterUpdater:willReloadIndexPaths:collectionView:","abstract":"\u003cp\u003eNotifies the delegate that the updater will call \u003ccode\u003e-[UICollectionView reloadItemsAtIndexPaths:]\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListAdapterUpdaterDelegate"},"Protocols/IGListAdapterUpdaterDelegate.html#/c:objc(pl)IGListAdapterUpdaterDelegate(im)listAdapterUpdater:willReloadSections:collectionView:":{"name":"-listAdapterUpdater:willReloadSections:collectionView:","abstract":"\u003cp\u003eNotifies the delegate that the updater will call \u003ccode\u003e-[UICollectionView reloadSections:]\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListAdapterUpdaterDelegate"},"Protocols/IGListAdapterUpdaterDelegate.html#/c:objc(pl)IGListAdapterUpdaterDelegate(im)listAdapterUpdater:willReloadDataWithCollectionView:isFallbackReload:":{"name":"-listAdapterUpdater:willReloadDataWithCollectionView:isFallbackReload:","abstract":"\u003cp\u003eNotifies the delegate that the updater will call \u003ccode\u003e-[UICollectionView reloadData]\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListAdapterUpdaterDelegate"},"Protocols/IGListAdapterUpdaterDelegate.html#/c:objc(pl)IGListAdapterUpdaterDelegate(im)listAdapterUpdater:didReloadDataWithCollectionView:isFallbackReload:":{"name":"-listAdapterUpdater:didReloadDataWithCollectionView:isFallbackReload:","abstract":"\u003cp\u003eNotifies the delegate that the updater successfully called \u003ccode\u003e-[UICollectionView reloadData]\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListAdapterUpdaterDelegate"},"Protocols/IGListAdapterUpdaterDelegate.html#/c:objc(pl)IGListAdapterUpdaterDelegate(im)listAdapterUpdater:collectionView:willCrashWithException:fromObjects:toObjects:diffResult:updates:":{"name":"-listAdapterUpdater:collectionView:willCrashWithException:fromObjects:toObjects:diffResult:updates:","abstract":"\u003cp\u003eNotifies the delegate that the collection view threw an exception in \u003ccode\u003e-[UICollectionView performBatchUpdates:completion:]\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListAdapterUpdaterDelegate"},"Protocols/IGListAdapterUpdaterDelegate.html#/c:objc(pl)IGListAdapterUpdaterDelegate(im)listAdapterUpdater:willCrashWithCollectionView:sectionControllerClass:":{"name":"-listAdapterUpdater:willCrashWithCollectionView:sectionControllerClass:","abstract":"\u003cp\u003eNotifies the delegate that the updater detected an imminent crash, such as when a section controller returns a nil cell.","parent_name":"IGListAdapterUpdaterDelegate"},"Protocols/IGListAdapterUpdaterDelegate.html#/c:objc(pl)IGListAdapterUpdaterDelegate(im)listAdapterUpdater:didFinishWithoutUpdatesWithCollectionView:":{"name":"-listAdapterUpdater:didFinishWithoutUpdatesWithCollectionView:","abstract":"\u003cp\u003eNotifies the delegate that the updater finished without performing any batch updates or reloads\u003c/p\u003e","parent_name":"IGListAdapterUpdaterDelegate"},"Protocols/IGListAdapterUpdateListener.html#/c:objc(pl)IGListAdapterUpdateListener(im)listAdapter:didFinishUpdate:animated:":{"name":"-listAdapter:didFinishUpdate:animated:","abstract":"\u003cp\u003eNotifies a listener that the listAdapter was updated.\u003c/p\u003e","parent_name":"IGListAdapterUpdateListener"},"Protocols/IGListAdapterPerformanceDelegate.html#/c:objc(pl)IGListAdapterPerformanceDelegate(im)listAdapterWillCallDequeueCell:":{"name":"-listAdapterWillCallDequeueCell:","abstract":"\u003cp\u003eWill call \u003ccode\u003e-[IGListAdapter collectionView:cellForItemAtIndexPath:]\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListAdapterPerformanceDelegate"},"Protocols/IGListAdapterPerformanceDelegate.html#/c:objc(pl)IGListAdapterPerformanceDelegate(im)listAdapter:didCallDequeueCell:onSectionController:atIndex:":{"name":"-listAdapter:didCallDequeueCell:onSectionController:atIndex:","abstract":"\u003cp\u003eDid finish calling \u003ccode\u003e-[IGListAdapter collectionView:cellForItemAtIndexPath:]\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListAdapterPerformanceDelegate"},"Protocols/IGListAdapterPerformanceDelegate.html#/c:objc(pl)IGListAdapterPerformanceDelegate(im)listAdapterWillCallDisplayCell:":{"name":"-listAdapterWillCallDisplayCell:","abstract":"\u003cp\u003eWill call \u003ccode\u003e-[IGListAdapter collectionView:willDisplayCell:forItemAtIndexPath:]\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListAdapterPerformanceDelegate"},"Protocols/IGListAdapterPerformanceDelegate.html#/c:objc(pl)IGListAdapterPerformanceDelegate(im)listAdapter:didCallDisplayCell:onSectionController:atIndex:":{"name":"-listAdapter:didCallDisplayCell:onSectionController:atIndex:","abstract":"\u003cp\u003eDid finish calling \u003ccode\u003e-[IGListAdapter collectionView:willDisplayCell:forItemAtIndexPath:]\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListAdapterPerformanceDelegate"},"Protocols/IGListAdapterPerformanceDelegate.html#/c:objc(pl)IGListAdapterPerformanceDelegate(im)listAdapterWillCallEndDisplayCell:":{"name":"-listAdapterWillCallEndDisplayCell:","abstract":"\u003cp\u003eWill call \u003ccode\u003e-[IGListAdapter collectionView:didEndDisplayingCell:forItemAtIndexPath:]\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListAdapterPerformanceDelegate"},"Protocols/IGListAdapterPerformanceDelegate.html#/c:objc(pl)IGListAdapterPerformanceDelegate(im)listAdapter:didCallEndDisplayCell:onSectionController:atIndex:":{"name":"-listAdapter:didCallEndDisplayCell:onSectionController:atIndex:","abstract":"\u003cp\u003eDid finish calling \u003ccode\u003e-[IGListAdapter collectionView:didEndDisplayingCell:forItemAtIndexPath:]\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListAdapterPerformanceDelegate"},"Protocols/IGListAdapterPerformanceDelegate.html#/c:objc(pl)IGListAdapterPerformanceDelegate(im)listAdapterWillCallSize:":{"name":"-listAdapterWillCallSize:","abstract":"\u003cp\u003eWill call \u003ccode\u003e-[IGListAdapter collectionView:collectionViewLayout:sizeForItemAtIndexPath:]\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListAdapterPerformanceDelegate"},"Protocols/IGListAdapterPerformanceDelegate.html#/c:objc(pl)IGListAdapterPerformanceDelegate(im)listAdapter:didCallSizeOnSectionController:atIndex:":{"name":"-listAdapter:didCallSizeOnSectionController:atIndex:","abstract":"\u003cp\u003eDid finish calling \u003ccode\u003e-[IGListAdapter collectionView:collectionViewLayout:sizeForItemAtIndexPath:]\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListAdapterPerformanceDelegate"},"Protocols/IGListAdapterPerformanceDelegate.html#/c:objc(pl)IGListAdapterPerformanceDelegate(im)listAdapterWillCallScroll:":{"name":"-listAdapterWillCallScroll:","abstract":"\u003cp\u003eWill call \u003ccode\u003e-[IGListAdapter scrollViewDidScroll:]\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListAdapterPerformanceDelegate"},"Protocols/IGListAdapterPerformanceDelegate.html#/c:objc(pl)IGListAdapterPerformanceDelegate(im)listAdapter:didCallScroll:":{"name":"-listAdapter:didCallScroll:","abstract":"\u003cp\u003eDid finish calling \u003ccode\u003e-[IGListAdapter scrollViewDidScroll:]\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListAdapterPerformanceDelegate"},"Protocols/IGListAdapterMoveDelegate.html#/c:objc(pl)IGListAdapterMoveDelegate(im)listAdapter:moveObject:from:to:":{"name":"-listAdapter:moveObject:from:to:","abstract":"\u003cp\u003eAsks the delegate to move a section object as the result of interactive reordering.\u003c/p\u003e","parent_name":"IGListAdapterMoveDelegate"},"Protocols/IGListAdapterDelegate.html#/c:objc(pl)IGListAdapterDelegate(im)listAdapter:willDisplayObject:atIndex:":{"name":"-listAdapter:willDisplayObject:atIndex:","abstract":"\u003cp\u003eNotifies the delegate that a list object is about to be displayed.\u003c/p\u003e","parent_name":"IGListAdapterDelegate"},"Protocols/IGListAdapterDelegate.html#/c:objc(pl)IGListAdapterDelegate(im)listAdapter:didEndDisplayingObject:atIndex:":{"name":"-listAdapter:didEndDisplayingObject:atIndex:","abstract":"\u003cp\u003eNotifies the delegate that a list object is no longer being displayed.\u003c/p\u003e","parent_name":"IGListAdapterDelegate"},"Protocols/IGListAdapterDelegate.html#/c:objc(pl)IGListAdapterDelegate(im)listAdapter:willDisplayObject:cell:atIndexPath:":{"name":"-listAdapter:willDisplayObject:cell:atIndexPath:","abstract":"\u003cp\u003eNotifies the delegate that a list object is about to be displayed.  This method is distinct from willDisplayObject:atIndex","parent_name":"IGListAdapterDelegate"},"Protocols/IGListAdapterDelegate.html#/c:objc(pl)IGListAdapterDelegate(im)listAdapter:didEndDisplayingObject:cell:atIndexPath:":{"name":"-listAdapter:didEndDisplayingObject:cell:atIndexPath:","abstract":"\u003cp\u003eNotifies the delegate that a list object is no longer being displayed.  This method is distinct from didEndDisplayingObject:atIndex","parent_name":"IGListAdapterDelegate"},"Protocols/IGListAdapterDataSource.html#/c:objc(pl)IGListAdapterDataSource(im)objectsForListAdapter:":{"name":"-objectsForListAdapter:","abstract":"\u003cp\u003eAsks the data source for the objects to display in the list.\u003c/p\u003e","parent_name":"IGListAdapterDataSource"},"Protocols/IGListAdapterDataSource.html#/c:objc(pl)IGListAdapterDataSource(im)listAdapter:sectionControllerForObject:":{"name":"-listAdapter:sectionControllerForObject:","abstract":"\u003cp\u003eAsks the data source for a section controller for the specified object in the list.\u003c/p\u003e","parent_name":"IGListAdapterDataSource"},"Protocols/IGListAdapterDataSource.html#/c:objc(pl)IGListAdapterDataSource(im)emptyViewForListAdapter:":{"name":"-emptyViewForListAdapter:","abstract":"\u003cp\u003eAsks the data source for a view to use as the collection view background when the list is empty.\u003c/p\u003e","parent_name":"IGListAdapterDataSource"},"Protocols/IGListDiffable.html#/c:objc(pl)IGListDiffable(im)diffIdentifier":{"name":"-diffIdentifier","abstract":"\u003cp\u003eReturns a key that uniquely identifies the object.\u003c/p\u003e","parent_name":"IGListDiffable"},"Protocols/IGListDiffable.html#/c:objc(pl)IGListDiffable(im)isEqualToDiffableObject:":{"name":"-isEqualToDiffableObject:","abstract":"\u003cp\u003eReturns whether the receiver and a given object are equal.\u003c/p\u003e","parent_name":"IGListDiffable"},"Protocols/IGListDiffable.html":{"name":"IGListDiffable","abstract":"\u003cp\u003eThe \u003ccode\u003eIGListDiffable\u003c/code\u003e protocol provides methods needed to compare the identity and equality of two objects.\u003c/p\u003e"},"Protocols/IGListAdapterDataSource.html":{"name":"IGListAdapterDataSource","abstract":"\u003cp\u003eImplement this protocol to provide data to an \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/IGListAdapter.html\"\u003eIGListAdapter\u003c/a\u003e\u003c/code\u003e.\u003c/p\u003e"},"Protocols/IGListAdapterDelegate.html":{"name":"IGListAdapterDelegate","abstract":"\u003cp\u003eConform to \u003ccode\u003eIGListAdapterDelegate\u003c/code\u003e to receive display events for objects in a list.\u003c/p\u003e"},"Protocols/IGListAdapterMoveDelegate.html":{"name":"IGListAdapterMoveDelegate","abstract":"\u003cp\u003eConform to \u003ccode\u003eIGListAdapterMoveDelegate\u003c/code\u003e to receive interactive reordering requests.\u003c/p\u003e"},"Protocols/IGListAdapterPerformanceDelegate.html":{"name":"IGListAdapterPerformanceDelegate","abstract":"\u003cp\u003e\u003ccode\u003eIGListAdapterPerformanceDelegate\u003c/code\u003e can be used to measure cell dequeue, display, size, and scroll callbacks.\u003c/p\u003e"},"Protocols/IGListAdapterUpdateListener.html":{"name":"IGListAdapterUpdateListener","abstract":"\u003cp\u003eConform to this protocol to receive events about \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/IGListAdapter.html\"\u003eIGListAdapter\u003c/a\u003e\u003c/code\u003e updates.\u003c/p\u003e"},"Protocols/IGListAdapterUpdaterDelegate.html":{"name":"IGListAdapterUpdaterDelegate","abstract":"\u003cp\u003eA protocol that receives events about \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/IGListAdapterUpdater.html\"\u003eIGListAdapterUpdater\u003c/a\u003e\u003c/code\u003e operations.\u003c/p\u003e"},"Protocols/IGListBatchContext.html":{"name":"IGListBatchContext","abstract":"\u003cp\u003eObjects conforming to the IGListBatchContext protocol provide a way for section controllers to mutate their cells or"},"Protocols/IGListBindable.html":{"name":"IGListBindable","abstract":"\u003cp\u003eA protocol for cells that configure themselves given a view model.\u003c/p\u003e"},"Protocols/IGListBindingSectionControllerDataSource.html":{"name":"IGListBindingSectionControllerDataSource","abstract":"\u003cp\u003eA protocol that returns data to power cells in an \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/IGListBindingSectionController.html\"\u003eIGListBindingSectionController\u003c/a\u003e\u003c/code\u003e.\u003c/p\u003e"},"Protocols/IGListBindingSectionControllerSelectionDelegate.html":{"name":"IGListBindingSectionControllerSelectionDelegate","abstract":"\u003cp\u003eA protocol that handles cell selection events in an \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/IGListBindingSectionController.html\"\u003eIGListBindingSectionController\u003c/a\u003e\u003c/code\u003e.\u003c/p\u003e"},"Protocols/IGListCollectionContext.html":{"name":"IGListCollectionContext","abstract":"\u003cp\u003eThe collection context provides limited access to the collection-related information that"},"Protocols/IGListCollectionViewDelegateLayout.html":{"name":"IGListCollectionViewDelegateLayout","abstract":"\u003cp\u003eConform to \u003ccode\u003eIGListCollectionViewDelegateLayout\u003c/code\u003e to provide customized layout information for a collection view.\u003c/p\u003e"},"Protocols/IGListCollectionViewLayoutCompatible.html":{"name":"IGListCollectionViewLayoutCompatible","abstract":"\u003cp\u003eA protocol for layouts that defines interaction with an IGListCollectionView, for recieving updated section indexes.\u003c/p\u003e"},"Protocols/IGListDisplayDelegate.html":{"name":"IGListDisplayDelegate","abstract":"\u003cp\u003eImplement this protocol to receive display events for a section controller when it is on screen.\u003c/p\u003e"},"Protocols/IGListScrollDelegate.html":{"name":"IGListScrollDelegate","abstract":"\u003cp\u003eImplement this protocol to receive display events for a section controller when it is on screen.\u003c/p\u003e"},"Protocols/IGListSingleSectionControllerDelegate.html":{"name":"IGListSingleSectionControllerDelegate","abstract":"\u003cp\u003eA delegate that can receive selection events on an \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/IGListSingleSectionController.html\"\u003eIGListSingleSectionController\u003c/a\u003e\u003c/code\u003e.\u003c/p\u003e"},"Protocols/IGListSupplementaryViewSource.html":{"name":"IGListSupplementaryViewSource","abstract":"\u003cp\u003eConform to this protocol to provide information about a list\u0026rsquo;s supplementary views. This data is used in"},"Protocols/IGListTransitionDelegate.html":{"name":"IGListTransitionDelegate","abstract":"\u003cp\u003eConform to \u003ccode\u003eIGListTransitionDelegate\u003c/code\u003e to provide customized layout information for a collection view.\u003c/p\u003e"},"Protocols/IGListUpdatingDelegate.html":{"name":"IGListUpdatingDelegate","abstract":"\u003cp\u003eImplement this protocol in order to handle both section and row based update events. Implementation should forward or"},"Protocols/IGListWorkingRangeDelegate.html":{"name":"IGListWorkingRangeDelegate","abstract":"\u003cp\u003eImplement this protocol to receive working range events for a list.\u003c/p\u003e"},"Enums/IGListAdapterUpdateType.html#/c:@E@IGListAdapterUpdateType@IGListAdapterUpdateTypePerformUpdates":{"name":"IGListAdapterUpdateTypePerformUpdates","abstract":"\u003cp\u003e\u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)performUpdatesAnimated:completion:\"\u003e-[IGListAdapter performUpdatesAnimated:completion:]\u003c/a\u003e\u003c/code\u003e was executed.\u003c/p\u003e","parent_name":"IGListAdapterUpdateType"},"Enums/IGListAdapterUpdateType.html#/c:@E@IGListAdapterUpdateType@IGListAdapterUpdateTypeReloadData":{"name":"IGListAdapterUpdateTypeReloadData","abstract":"\u003cp\u003e\u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)reloadDataWithCompletion:\"\u003e-[IGListAdapter reloadDataWithCompletion:]\u003c/a\u003e\u003c/code\u003e was executed.\u003c/p\u003e","parent_name":"IGListAdapterUpdateType"},"Enums/IGListAdapterUpdateType.html#/c:@E@IGListAdapterUpdateType@IGListAdapterUpdateTypeItemUpdates":{"name":"IGListAdapterUpdateTypeItemUpdates","abstract":"\u003cp\u003e\u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbProtocols/IGListCollectionContext.html#/c:objc(pl)IGListCollectionContext(im)performBatchAnimated:updates:completion:\"\u003e-[IGListCollectionContext performBatchAnimated:updates:completion:]\u003c/a\u003e\u003c/code\u003e was executed by an \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/IGListSectionController.html\"\u003eIGListSectionController\u003c/a\u003e\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListAdapterUpdateType"},"Enums/IGListExperiment.html#/c:@E@IGListExperiment@IGListExperimentNone":{"name":"IGListExperimentNone","abstract":"\u003cp\u003eSpecifies no experiments.\u003c/p\u003e","parent_name":"IGListExperiment"},"Enums/IGListExperiment.html#/c:@E@IGListExperiment@IGListExperimentInvalidateLayoutForUpdates":{"name":"IGListExperimentInvalidateLayoutForUpdates","abstract":"\u003cp\u003eTest invalidating layout when cell reloads/updates in IGListBindingSectionController.\u003c/p\u003e","parent_name":"IGListExperiment"},"Enums/IGListExperiment.html#/c:@E@IGListExperiment@IGListExperimentThrowOnInconsistencyException":{"name":"IGListExperimentThrowOnInconsistencyException","abstract":"\u003cp\u003eThrow NSInternalInconsistencyException during an update\u003c/p\u003e","parent_name":"IGListExperiment"},"Enums/IGListExperiment.html#/c:@E@IGListExperiment@IGListExperimentRemoveDataSourceChangeEarlyExit":{"name":"IGListExperimentRemoveDataSourceChangeEarlyExit","abstract":"\u003cp\u003eRemove the early exit so multiple updates can\u0026rsquo;t happen at once\u003c/p\u003e","parent_name":"IGListExperiment"},"Enums/IGListExperiment.html#/c:@E@IGListExperiment@IGListExperimentFixPreferredFocusedView":{"name":"IGListExperimentFixPreferredFocusedView","abstract":"\u003cp\u003eAvoids creating off-screen cells\u003c/p\u003e","parent_name":"IGListExperiment"},"Enums/IGListDiffOption.html#/c:@E@IGListDiffOption@IGListDiffPointerPersonality":{"name":"IGListDiffPointerPersonality","abstract":"\u003cp\u003eCompare objects using pointer personality.\u003c/p\u003e","parent_name":"IGListDiffOption"},"Enums/IGListDiffOption.html#/c:@E@IGListDiffOption@IGListDiffEquality":{"name":"IGListDiffEquality","abstract":"\u003cp\u003eCompare objects using \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbProtocols/IGListDiffable.html#/c:objc(pl)IGListDiffable(im)isEqualToDiffableObject:\"\u003e-[IGListDiffable isEqualToDiffableObject:]\u003c/a\u003e\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListDiffOption"},"Enums/IGListDiffOption.html":{"name":"IGListDiffOption","abstract":"\u003cp\u003eAn option for how to do comparisons between similar objects.\u003c/p\u003e"},"Enums/IGListExperiment.html":{"name":"IGListExperiment","abstract":"\u003cp\u003eBitmask-able options used for pre-release feature testing.\u003c/p\u003e"},"Enums/IGListAdapterUpdateType.html":{"name":"IGListAdapterUpdateType","abstract":"\u003cp\u003eThe type of update that was performed by an \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/IGListAdapter.html\"\u003eIGListAdapter\u003c/a\u003e\u003c/code\u003e.\u003c/p\u003e"},"Constants.html#/c:@IGListKitVersionNumber":{"name":"IGListKitVersionNumber","abstract":"\u003cp\u003eProject version number for IGListKit.\u003c/p\u003e"},"Constants.html#/c:@IGListKitVersionString":{"name":"IGListKitVersionString","abstract":"\u003cp\u003eProject version string for IGListKit.\u003c/p\u003e"},"Classes/IGListTransitionData.html#/c:objc(cs)IGListTransitionData(im)initFromObjects:toObjects:toSectionControllers:":{"name":"-initFromObjects:toObjects:toSectionControllers:","abstract":"\u003cp\u003eUndocumented\u003c/p\u003e","parent_name":"IGListTransitionData"},"Classes/IGListTransitionData.html#/c:objc(cs)IGListTransitionData(im)init":{"name":"-init","abstract":"\u003cp\u003eUndocumented\u003c/p\u003e","parent_name":"IGListTransitionData"},"Classes/IGListTransitionData.html#/c:objc(cs)IGListTransitionData(cm)new":{"name":"+new","abstract":"\u003cp\u003eUndocumented\u003c/p\u003e","parent_name":"IGListTransitionData"},"Classes/IGListTransitionData.html#/c:objc(cs)IGListTransitionData(py)fromObjects":{"name":"fromObjects","abstract":"\u003cp\u003eThe previous objects in the collection view. Objects must conform to \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbProtocols/IGListDiffable.html\"\u003eIGListDiffable\u003c/a\u003e\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListTransitionData"},"Classes/IGListTransitionData.html#/c:objc(cs)IGListTransitionData(py)toObjects":{"name":"toObjects","abstract":"\u003cp\u003eThe new objects in the collection view. Objects must conform to \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbProtocols/IGListDiffable.html\"\u003eIGListDiffable\u003c/a\u003e\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListTransitionData"},"Classes/IGListTransitionData.html#/c:objc(cs)IGListTransitionData(py)toSectionControllers":{"name":"toSectionControllers","abstract":"\u003cp\u003eThe section controllers corresponding to the \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/IGListTransitionData.html#/c:objc(cs)IGListTransitionData(py)toObjects\"\u003etoObjects\u003c/a\u003e\u003c/code\u003e\u003c/p\u003e","parent_name":"IGListTransitionData"},"Classes/IGListSingleSectionController.html#/c:objc(cs)IGListSingleSectionController(im)initWithCellClass:configureBlock:sizeBlock:":{"name":"-initWithCellClass:configureBlock:sizeBlock:","abstract":"\u003cp\u003eCreates a new section controller for a given cell type that will always have only one cell when present in a list.\u003c/p\u003e","parent_name":"IGListSingleSectionController"},"Classes/IGListSingleSectionController.html#/c:objc(cs)IGListSingleSectionController(im)initWithNibName:bundle:configureBlock:sizeBlock:":{"name":"-initWithNibName:bundle:configureBlock:sizeBlock:","abstract":"\u003cp\u003eCreates a new section controller for a given nib name and bundle that will always have only one cell when present in a list.\u003c/p\u003e","parent_name":"IGListSingleSectionController"},"Classes/IGListSingleSectionController.html#/c:objc(cs)IGListSingleSectionController(im)initWithStoryboardCellIdentifier:configureBlock:sizeBlock:":{"name":"-initWithStoryboardCellIdentifier:configureBlock:sizeBlock:","abstract":"\u003cp\u003eCreates a new section controller for a given storyboard cell identifier that will always have only one cell when present in a list.\u003c/p\u003e","parent_name":"IGListSingleSectionController"},"Classes/IGListSingleSectionController.html#/c:objc(cs)IGListSingleSectionController(py)selectionDelegate":{"name":"selectionDelegate","abstract":"\u003cp\u003eAn optional delegate that handles selection and deselection.\u003c/p\u003e","parent_name":"IGListSingleSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(im)numberOfItems":{"name":"-numberOfItems","abstract":"\u003cp\u003eReturns the number of items in the section.\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(im)sizeForItemAtIndex:":{"name":"-sizeForItemAtIndex:","abstract":"\u003cp\u003eThe specific size for the item at the specified index.\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(im)cellForItemAtIndex:":{"name":"-cellForItemAtIndex:","abstract":"\u003cp\u003eReturn a dequeued cell for a given index.\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(im)didUpdateToObject:":{"name":"-didUpdateToObject:","abstract":"\u003cp\u003eUpdates the section controller to a new object.\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(im)shouldSelectItemAtIndex:":{"name":"-shouldSelectItemAtIndex:","abstract":"\u003cp\u003eAsks the section controller if the cell at the specified index path should be selected\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(im)shouldDeselectItemAtIndex:":{"name":"-shouldDeselectItemAtIndex:","abstract":"\u003cp\u003eAsks the section controller if the cell at the specified index path should be deselected\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(im)didSelectItemAtIndex:":{"name":"-didSelectItemAtIndex:","abstract":"\u003cp\u003eTells the section controller that the cell at the specified index path was selected.\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(im)didDeselectItemAtIndex:":{"name":"-didDeselectItemAtIndex:","abstract":"\u003cp\u003eTells the section controller that the cell at the specified index path was deselected.\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(im)didHighlightItemAtIndex:":{"name":"-didHighlightItemAtIndex:","abstract":"\u003cp\u003eTells the section controller that the cell at the specified index path was highlighted.\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(im)didUnhighlightItemAtIndex:":{"name":"-didUnhighlightItemAtIndex:","abstract":"\u003cp\u003eTells the section controller that the cell at the specified index path was unhighlighted.\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(im)contextMenuConfigurationForItemAtIndex:point:":{"name":"-contextMenuConfigurationForItemAtIndex:point:","abstract":"\u003cp\u003eTells the section controller that the cell has requested a menu configuration.\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(im)canMoveItemAtIndex:":{"name":"-canMoveItemAtIndex:","abstract":"\u003cp\u003eIdentifies whether an object can be moved through interactive reordering.\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(im)moveObjectFromIndex:toIndex:":{"name":"-moveObjectFromIndex:toIndex:","abstract":"\u003cp\u003eNotifies the section that a list object should move within a section as the result of interactive reordering.\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(py)viewController":{"name":"viewController","abstract":"\u003cp\u003eThe view controller housing the adapter that created this section controller.\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(py)collectionContext":{"name":"collectionContext","abstract":"\u003cp\u003eA context object for interacting with the collection.\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(py)section":{"name":"section","abstract":"\u003cp\u003eReturns the section within the list for this section controller.\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(py)isFirstSection":{"name":"isFirstSection","abstract":"\u003cp\u003eReturns \u003ccode\u003eYES\u003c/code\u003e if the section controller is the first section in the list, \u003ccode\u003eNO\u003c/code\u003e otherwise.\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(py)isLastSection":{"name":"isLastSection","abstract":"\u003cp\u003eReturns \u003ccode\u003eYES\u003c/code\u003e if the section controller is the last section in the list, \u003ccode\u003eNO\u003c/code\u003e otherwise.\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(py)inset":{"name":"inset","abstract":"\u003cp\u003eThe margins used to lay out content in the section controller.\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(py)minimumLineSpacing":{"name":"minimumLineSpacing","abstract":"\u003cp\u003eThe minimum spacing to use between rows of items.\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(py)minimumInteritemSpacing":{"name":"minimumInteritemSpacing","abstract":"\u003cp\u003eThe minimum spacing to use between items in the same row.\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(py)supplementaryViewSource":{"name":"supplementaryViewSource","abstract":"\u003cp\u003eThe supplementary view source for the section controller. Can be \u003ccode\u003enil\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(py)displayDelegate":{"name":"displayDelegate","abstract":"\u003cp\u003eAn object that handles display events for the section controller. Can be \u003ccode\u003enil\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(py)workingRangeDelegate":{"name":"workingRangeDelegate","abstract":"\u003cp\u003eAn object that handles working range events for the section controller. Can be \u003ccode\u003enil\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(py)scrollDelegate":{"name":"scrollDelegate","abstract":"\u003cp\u003eAn object that handles scroll events for the section controller. Can be \u003ccode\u003enil\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListSectionController.html#/c:objc(cs)IGListSectionController(py)transitionDelegate":{"name":"transitionDelegate","abstract":"\u003cp\u003eAn object that handles transition events for the section controller. Can be \u003ccode\u003enil\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListSectionController"},"Classes/IGListGenericSectionController.html#/c:objc(cs)IGListGenericSectionController(py)object":{"name":"object","abstract":"\u003cp\u003eThe object mapped to this section controller. Matches the object provided in","parent_name":"IGListGenericSectionController"},"Classes/IGListGenericSectionController.html#/c:objc(cs)IGListGenericSectionController(im)didUpdateToObject:":{"name":"-didUpdateToObject:","abstract":"\u003cp\u003eUpdates the section controller to a new object.\u003c/p\u003e","parent_name":"IGListGenericSectionController"},"Classes/IGListCollectionViewLayoutInvalidationContext.html#/c:objc(cs)IGListCollectionViewLayoutInvalidationContext(py)invalidateSupplementaryListAttributes":{"name":"invalidateSupplementaryListAttributes","abstract":"\u003cp\u003eFalse by default. If true, supplementary list item attributes (headers and footers) will be invalidated.\u003c/p\u003e","parent_name":"IGListCollectionViewLayoutInvalidationContext"},"Classes/IGListCollectionViewLayoutInvalidationContext.html#/c:objc(cs)IGListCollectionViewLayoutInvalidationContext(py)invalidateAllListAttributes":{"name":"invalidateAllListAttributes","abstract":"\u003cp\u003eFalse by default. If true, all list item attributes will be invalidated.\u003c/p\u003e","parent_name":"IGListCollectionViewLayoutInvalidationContext"},"Classes/IGListCollectionViewLayout.html#/c:objc(cs)IGListCollectionViewLayout(py)scrollDirection":{"name":"scrollDirection","abstract":"\u003cp\u003eDirection in which layout will be scrollable; items will be flowed in the perpendicular direction, \u0026ldquo;newlining\u0026rdquo; when they","parent_name":"IGListCollectionViewLayout"},"Classes/IGListCollectionViewLayout.html#/c:objc(cs)IGListCollectionViewLayout(py)stickyHeaderYOffset":{"name":"stickyHeaderYOffset","abstract":"\u003cp\u003eSet this to adjust the offset of the sticky headers in the scrolling direction. Can be used to change the sticky","parent_name":"IGListCollectionViewLayout"},"Classes/IGListCollectionViewLayout.html#/c:objc(cs)IGListCollectionViewLayout(py)showHeaderWhenEmpty":{"name":"showHeaderWhenEmpty","abstract":"\u003cp\u003eSet this to \u003ccode\u003eYES\u003c/code\u003e to show sticky header when a section had no item. Default is \u003ccode\u003eNO\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListCollectionViewLayout"},"Classes/IGListCollectionViewLayout.html#/c:objc(cs)IGListCollectionViewLayout(py)preserveLayoutCacheOnInvalidateLayout":{"name":"preserveLayoutCacheOnInvalidateLayout","abstract":"\u003cp\u003eSet this to \u003ccode\u003eYES\u003c/code\u003e to keep layout cache when invalidateLayout is called. Default is \u003ccode\u003eNO\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListCollectionViewLayout"},"Classes/IGListCollectionViewLayout.html#/c:objc(cs)IGListCollectionViewLayout(im)initWithStickyHeaders:scrollDirection:topContentInset:stretchToEdge:":{"name":"-initWithStickyHeaders:scrollDirection:topContentInset:stretchToEdge:","abstract":"\u003cp\u003eCreate and return a new collection view layout.\u003c/p\u003e","parent_name":"IGListCollectionViewLayout"},"Classes/IGListCollectionViewLayout.html#/c:objc(cs)IGListCollectionViewLayout(im)initWithStickyHeaders:topContentInset:stretchToEdge:":{"name":"-initWithStickyHeaders:topContentInset:stretchToEdge:","abstract":"\u003cp\u003eCreate and return a new vertically scrolling collection view layout.\u003c/p\u003e","parent_name":"IGListCollectionViewLayout"},"Classes/IGListCollectionView.html#/c:objc(cs)IGListCollectionView(im)initWithFrame:listCollectionViewLayout:":{"name":"-initWithFrame:listCollectionViewLayout:","abstract":"\u003cp\u003eCreate a new view with an \u003ccode\u003eIGListcollectionViewLayout\u003c/code\u003e class or subclass.\u003c/p\u003e","parent_name":"IGListCollectionView"},"Classes/IGListBindingSingleSectionController.html#/c:objc(cs)IGListBindingSingleSectionController(im)cellClass":{"name":"-cellClass","abstract":"\u003cp\u003eUndocumented\u003c/p\u003e","parent_name":"IGListBindingSingleSectionController"},"Classes/IGListBindingSingleSectionController.html#/c:objc(cs)IGListBindingSingleSectionController(im)configureCell:withViewModel:":{"name":"-configureCell:withViewModel:","abstract":"\u003cp\u003eUndocumented\u003c/p\u003e","parent_name":"IGListBindingSingleSectionController"},"Classes/IGListBindingSingleSectionController.html#/c:objc(cs)IGListBindingSingleSectionController(im)sizeForViewModel:":{"name":"-sizeForViewModel:","abstract":"\u003cp\u003eUndocumented\u003c/p\u003e","parent_name":"IGListBindingSingleSectionController"},"Classes/IGListBindingSingleSectionController.html#/c:objc(cs)IGListBindingSingleSectionController(im)didSelectItemWithCell:":{"name":"-didSelectItemWithCell:","abstract":"\u003cp\u003eUndocumented\u003c/p\u003e","parent_name":"IGListBindingSingleSectionController"},"Classes/IGListBindingSingleSectionController.html#/c:objc(cs)IGListBindingSingleSectionController(im)didDeselectItemWithCell:":{"name":"-didDeselectItemWithCell:","abstract":"\u003cp\u003eUndocumented\u003c/p\u003e","parent_name":"IGListBindingSingleSectionController"},"Classes/IGListBindingSingleSectionController.html#/c:objc(cs)IGListBindingSingleSectionController(im)didHighlightItemWithCell:":{"name":"-didHighlightItemWithCell:","abstract":"\u003cp\u003eUndocumented\u003c/p\u003e","parent_name":"IGListBindingSingleSectionController"},"Classes/IGListBindingSingleSectionController.html#/c:objc(cs)IGListBindingSingleSectionController(im)didUnhighlightItemWithCell:":{"name":"-didUnhighlightItemWithCell:","abstract":"\u003cp\u003eUndocumented\u003c/p\u003e","parent_name":"IGListBindingSingleSectionController"},"Classes/IGListBindingSingleSectionController.html#/c:objc(cs)IGListBindingSingleSectionController(im)isDisplayingCell":{"name":"-isDisplayingCell","abstract":"\u003cp\u003eUndocumented\u003c/p\u003e","parent_name":"IGListBindingSingleSectionController"},"Classes/IGListBindingSectionController.html#/c:objc(cs)IGListBindingSectionController(py)dataSource":{"name":"dataSource","abstract":"\u003cp\u003eA data source that transforms a top-level object into view models, and returns cells and sizes for given view models.\u003c/p\u003e","parent_name":"IGListBindingSectionController"},"Classes/IGListBindingSectionController.html#/c:objc(cs)IGListBindingSectionController(py)selectionDelegate":{"name":"selectionDelegate","abstract":"\u003cp\u003eA delegate that receives selection events from cells in an \u003ccode\u003eIGListBindingSectionController\u003c/code\u003e instance.\u003c/p\u003e","parent_name":"IGListBindingSectionController"},"Classes/IGListBindingSectionController.html#/c:objc(cs)IGListBindingSectionController(py)object":{"name":"object","abstract":"\u003cp\u003eThe object currently assigned to the section controller, if any.\u003c/p\u003e","parent_name":"IGListBindingSectionController"},"Classes/IGListBindingSectionController.html#/c:objc(cs)IGListBindingSectionController(py)viewModels":{"name":"viewModels","abstract":"\u003cp\u003eThe array of view models created from the data source. Values are changed when the top-level object changes or by","parent_name":"IGListBindingSectionController"},"Classes/IGListBindingSectionController.html#/c:objc(cs)IGListBindingSectionController(im)updateAnimated:completion:":{"name":"-updateAnimated:completion:","abstract":"\u003cp\u003eTells the section controller to query for new view models, diff the changes, and update its cells.\u003c/p\u003e","parent_name":"IGListBindingSectionController"},"Classes/IGListBindingSectionController.html#/c:objc(cs)IGListBindingSectionController(im)moveObjectFromIndex:toIndex:":{"name":"-moveObjectFromIndex:toIndex:","abstract":"\u003cp\u003eNotifies the section that a list object should move within a section as the result of interactive reordering.\u003c/p\u003e","parent_name":"IGListBindingSectionController"},"Classes/IGListAdapterUpdater.html#/c:objc(cs)IGListAdapterUpdater(py)delegate":{"name":"delegate","abstract":"\u003cp\u003eThe delegate that receives events with data on the performance of a transition.\u003c/p\u003e","parent_name":"IGListAdapterUpdater"},"Classes/IGListAdapterUpdater.html#/c:objc(cs)IGListAdapterUpdater(py)sectionMovesAsDeletesInserts":{"name":"sectionMovesAsDeletesInserts","abstract":"\u003cp\u003eA flag indicating if a section move should be treated as a section \u0026ldquo;delete, then insert\u0026rdquo; operation. This can be useful if you\u0026rsquo;re","parent_name":"IGListAdapterUpdater"},"Classes/IGListAdapterUpdater.html#/c:objc(cs)IGListAdapterUpdater(py)singleItemSectionUpdates":{"name":"singleItemSectionUpdates","abstract":"\u003cp\u003eONLY used when there is N section, but each section only contains 1 item.","parent_name":"IGListAdapterUpdater"},"Classes/IGListAdapterUpdater.html#/c:objc(cs)IGListAdapterUpdater(py)preferItemReloadsForSectionReloads":{"name":"preferItemReloadsForSectionReloads","abstract":"\u003cp\u003eA flag indicating that section reloads should be treated as item reloads, instead of converting them to \u0026ldquo;delete, then insert\u0026rdquo; operations.","parent_name":"IGListAdapterUpdater"},"Classes/IGListAdapterUpdater.html#/c:objc(cs)IGListAdapterUpdater(py)allowsReloadingOnTooManyUpdates":{"name":"allowsReloadingOnTooManyUpdates","abstract":"\u003cp\u003eIf there\u0026rsquo;s more than 100 diff updates, fallback to using \u003ccode\u003ereloadData\u003c/code\u003e to avoid stalling the main thread.\u003c/p\u003e","parent_name":"IGListAdapterUpdater"},"Classes/IGListAdapterUpdater.html#/c:objc(cs)IGListAdapterUpdater(py)allowsBackgroundDiffing":{"name":"allowsBackgroundDiffing","abstract":"\u003cp\u003eAllow the diffing to be performed on a background thread.\u003c/p\u003e","parent_name":"IGListAdapterUpdater"},"Classes/IGListAdapterUpdater.html#/c:objc(cs)IGListAdapterUpdater(py)experiments":{"name":"experiments","abstract":"\u003cp\u003eA bitmask of experiments to conduct on the updater.\u003c/p\u003e","parent_name":"IGListAdapterUpdater"},"Classes/IGListAdapterUpdater.html#/c:objc(cs)IGListAdapterUpdater(py)adaptiveDiffingExperimentConfig":{"name":"adaptiveDiffingExperimentConfig","abstract":"\u003cp\u003eThis is an experimental feature to customize how diffing is performed. If there’s clear value, we’ll make this a real API and make","parent_name":"IGListAdapterUpdater"},"Classes/IGListAdapterUpdater.html#/c:objc(cs)IGListAdapterUpdater(py)adaptiveCoalescingExperimentConfig":{"name":"adaptiveCoalescingExperimentConfig","abstract":"\u003cp\u003eCustomize how coalescing works to speed up some updates\u003c/p\u003e","parent_name":"IGListAdapterUpdater"},"Classes/IGListAdapterDelegateAnnouncer.html#/c:objc(cs)IGListAdapterDelegateAnnouncer(cm)sharedInstance":{"name":"+sharedInstance","abstract":"\u003cp\u003eDefault announcer for all \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/IGListAdapter.html\"\u003eIGListAdapter\u003c/a\u003e\u003c/code\u003e\u003c/p\u003e","parent_name":"IGListAdapterDelegateAnnouncer"},"Classes/IGListAdapterDelegateAnnouncer.html#/c:objc(cs)IGListAdapterDelegateAnnouncer(im)addListener:":{"name":"-addListener:","abstract":"\u003cp\u003eAdd a delegate that will receive callbacks for all \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/IGListAdapter.html\"\u003eIGListAdapter\u003c/a\u003e\u003c/code\u003e.","parent_name":"IGListAdapterDelegateAnnouncer"},"Classes/IGListAdapterDelegateAnnouncer.html#/c:objc(cs)IGListAdapterDelegateAnnouncer(im)removeListener:":{"name":"-removeListener:","abstract":"\u003cp\u003eRemove delegate\u003c/p\u003e","parent_name":"IGListAdapterDelegateAnnouncer"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(py)viewController":{"name":"viewController","abstract":"\u003cp\u003eThe view controller that houses the adapter.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(py)collectionView":{"name":"collectionView","abstract":"\u003cp\u003eThe collection view used with the adapter.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(py)dataSource":{"name":"dataSource","abstract":"\u003cp\u003eThe object that acts as the data source for the adapter.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(py)delegate":{"name":"delegate","abstract":"\u003cp\u003eThe object that receives top-level events for section controllers.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(py)collectionViewDelegate":{"name":"collectionViewDelegate","abstract":"\u003cp\u003eThe object that receives \u003ccode\u003eUICollectionViewDelegate\u003c/code\u003e events.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(py)scrollViewDelegate":{"name":"scrollViewDelegate","abstract":"\u003cp\u003eThe object that receives \u003ccode\u003eUIScrollViewDelegate\u003c/code\u003e events.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(py)moveDelegate":{"name":"moveDelegate","abstract":"\u003cp\u003eThe object that receives \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbProtocols/IGListAdapterMoveDelegate.html\"\u003eIGListAdapterMoveDelegate\u003c/a\u003e\u003c/code\u003e events resulting from interactive reordering of sections.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(py)performanceDelegate":{"name":"performanceDelegate","abstract":"\u003cp\u003eThe object that receives \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbProtocols/IGListAdapterPerformanceDelegate.html\"\u003eIGListAdapterPerformanceDelegate\u003c/a\u003e\u003c/code\u003e events to measure performance.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(py)updater":{"name":"updater","abstract":"\u003cp\u003eThe updater for the adapter.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(py)experiments":{"name":"experiments","abstract":"\u003cp\u003eA bitmask of experiments to conduct on the adapter.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(py)autoDeselectEnabled":{"name":"autoDeselectEnabled","abstract":"\u003cp\u003eWhen true, we automatically deselect cells after they are selected (animated), so each section-controller doesn\u0026rsquo;t have to.","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)initWithUpdater:viewController:workingRangeSize:":{"name":"-initWithUpdater:viewController:workingRangeSize:","abstract":"\u003cp\u003eInitializes a new \u003ccode\u003eIGListAdapter\u003c/code\u003e object.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)initWithUpdater:viewController:":{"name":"-initWithUpdater:viewController:","abstract":"\u003cp\u003eInitializes a new \u003ccode\u003eIGListAdapter\u003c/code\u003e object with a working range of \u003ccode\u003e0\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)performUpdatesAnimated:completion:":{"name":"-performUpdatesAnimated:completion:","abstract":"\u003cp\u003ePerform an update from the previous state of the data source. This is analogous to calling","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)reloadDataWithCompletion:":{"name":"-reloadDataWithCompletion:","abstract":"\u003cp\u003ePerform an immediate reload of the data in the data source, discarding the old objects.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)reloadObjects:":{"name":"-reloadObjects:","abstract":"\u003cp\u003eReload the list for only the specified objects.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)sectionControllerForSection:":{"name":"-sectionControllerForSection:","abstract":"\u003cp\u003eQuery the section controller at a given section index. Constant time lookup.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)sectionForSectionController:":{"name":"-sectionForSectionController:","abstract":"\u003cp\u003eQuery the section index of a list. Constant time lookup.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)sectionControllerForObject:":{"name":"-sectionControllerForObject:","abstract":"\u003cp\u003eReturns the section controller for the specified object. Constant time lookup.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)objectForSectionController:":{"name":"-objectForSectionController:","abstract":"\u003cp\u003eReturns the object corresponding to the specified section controller in the list. Constant time lookup.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)objectAtSection:":{"name":"-objectAtSection:","abstract":"\u003cp\u003eReturns the object corresponding to a section in the list. Constant time lookup.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)sectionForObject:":{"name":"-sectionForObject:","abstract":"\u003cp\u003eReturns the section corresponding to the specified object in the list. Constant time lookup.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)objects":{"name":"-objects","abstract":"\u003cp\u003eReturns a copy of all the objects currently driving the adapter.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)visibleSectionControllers":{"name":"-visibleSectionControllers","abstract":"\u003cp\u003eAn unordered array of the currently visible section controllers.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)visibleObjects":{"name":"-visibleObjects","abstract":"\u003cp\u003eAn unordered array of the currently visible objects.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)indexesOfVisibleObjects":{"name":"-indexesOfVisibleObjects","abstract":"\u003cp\u003eLess performant that \u003ccode\u003evisibleObjects\u003c/code\u003e but gives you an ordering to the list of visible objects in \u003ccode\u003eself.objects\u003c/code\u003e.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)visibleCellsForObject:":{"name":"-visibleCellsForObject:","abstract":"\u003cp\u003eAn unordered array of the currently visible cells for a given object.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)scrollToObject:supplementaryKinds:scrollDirection:scrollPosition:additionalOffset:animated:":{"name":"-scrollToObject:supplementaryKinds:scrollDirection:scrollPosition:additionalOffset:animated:","abstract":"\u003cp\u003eScrolls to the specified object in the list adapter.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)indexPathForFirstVisibleItem":{"name":"-indexPathForFirstVisibleItem","abstract":"\u003cp\u003eReturns the index path for the first visible cell that has been scrolled to.","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)offsetForFirstVisibleItemWithScrollDirection:":{"name":"-offsetForFirstVisibleItemWithScrollDirection:","abstract":"\u003cp\u003eGets the scroll offset of the first visible cell scrolled into in the collection view.","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)sizeForItemAtIndexPath:":{"name":"-sizeForItemAtIndexPath:","abstract":"\u003cp\u003eReturns the size of a cell at the specified index path.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)sizeForSupplementaryViewOfKind:atIndexPath:":{"name":"-sizeForSupplementaryViewOfKind:atIndexPath:","abstract":"\u003cp\u003eReturns the size of a supplementary view in the list at the specified index path.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)addUpdateListener:":{"name":"-addUpdateListener:","abstract":"\u003cp\u003eAdds a listener to the list adapter.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListAdapter.html#/c:objc(cs)IGListAdapter(im)removeUpdateListener:":{"name":"-removeUpdateListener:","abstract":"\u003cp\u003eRemoves a listener from the list adapter.\u003c/p\u003e","parent_name":"IGListAdapter"},"Classes/IGListMoveIndexPath.html#/c:objc(cs)IGListMoveIndexPath(py)from":{"name":"from","abstract":"\u003cp\u003eAn index path in the old collection.\u003c/p\u003e","parent_name":"IGListMoveIndexPath"},"Classes/IGListMoveIndexPath.html#/c:objc(cs)IGListMoveIndexPath(py)to":{"name":"to","abstract":"\u003cp\u003eAn index path in the new collection.\u003c/p\u003e","parent_name":"IGListMoveIndexPath"},"Classes/IGListMoveIndex.html#/c:objc(cs)IGListMoveIndex(py)from":{"name":"from","abstract":"\u003cp\u003eAn index in the old collection.\u003c/p\u003e","parent_name":"IGListMoveIndex"},"Classes/IGListMoveIndex.html#/c:objc(cs)IGListMoveIndex(py)to":{"name":"to","abstract":"\u003cp\u003eAn index in the new collection.\u003c/p\u003e","parent_name":"IGListMoveIndex"},"Classes/IGListIndexSetResult.html#/c:objc(cs)IGListIndexSetResult(py)inserts":{"name":"inserts","abstract":"\u003cp\u003eThe indexes inserted into the new collection.\u003c/p\u003e","parent_name":"IGListIndexSetResult"},"Classes/IGListIndexSetResult.html#/c:objc(cs)IGListIndexSetResult(py)deletes":{"name":"deletes","abstract":"\u003cp\u003eThe indexes deleted from the old collection.\u003c/p\u003e","parent_name":"IGListIndexSetResult"},"Classes/IGListIndexSetResult.html#/c:objc(cs)IGListIndexSetResult(py)updates":{"name":"updates","abstract":"\u003cp\u003eThe indexes in the old collection that need updated.\u003c/p\u003e","parent_name":"IGListIndexSetResult"},"Classes/IGListIndexSetResult.html#/c:objc(cs)IGListIndexSetResult(py)moves":{"name":"moves","abstract":"\u003cp\u003eThe moves from an index in the old collection to an index in the new collection.\u003c/p\u003e","parent_name":"IGListIndexSetResult"},"Classes/IGListIndexSetResult.html#/c:objc(cs)IGListIndexSetResult(py)hasChanges":{"name":"hasChanges","abstract":"\u003cp\u003eA Read-only boolean that indicates whether the result has any changes or not.","parent_name":"IGListIndexSetResult"},"Classes/IGListIndexSetResult.html#/c:objc(cs)IGListIndexSetResult(im)oldIndexForIdentifier:":{"name":"-oldIndexForIdentifier:","abstract":"\u003cp\u003eReturns the index of the object with the specified identifier \u003cem\u003ebefore\u003c/em\u003e the diff.\u003c/p\u003e","parent_name":"IGListIndexSetResult"},"Classes/IGListIndexSetResult.html#/c:objc(cs)IGListIndexSetResult(im)newIndexForIdentifier:":{"name":"-newIndexForIdentifier:","abstract":"\u003cp\u003eReturns the index of the object with the specified identifier \u003cem\u003eafter\u003c/em\u003e the diff.\u003c/p\u003e","parent_name":"IGListIndexSetResult"},"Classes/IGListIndexSetResult.html#/c:objc(cs)IGListIndexSetResult(im)resultForBatchUpdates":{"name":"-resultForBatchUpdates","abstract":"\u003cp\u003eCreates a new result object with operations safe for use in \u003ccode\u003eUITableView\u003c/code\u003e and \u003ccode\u003eUICollectionView\u003c/code\u003e batch updates.\u003c/p\u003e","parent_name":"IGListIndexSetResult"},"Classes/IGListIndexPathResult.html#/c:objc(cs)IGListIndexPathResult(py)inserts":{"name":"inserts","abstract":"\u003cp\u003eThe index paths inserted into the new collection.\u003c/p\u003e","parent_name":"IGListIndexPathResult"},"Classes/IGListIndexPathResult.html#/c:objc(cs)IGListIndexPathResult(py)deletes":{"name":"deletes","abstract":"\u003cp\u003eThe index paths deleted from the old collection.\u003c/p\u003e","parent_name":"IGListIndexPathResult"},"Classes/IGListIndexPathResult.html#/c:objc(cs)IGListIndexPathResult(py)updates":{"name":"updates","abstract":"\u003cp\u003eThe index paths in the old collection that need updated.\u003c/p\u003e","parent_name":"IGListIndexPathResult"},"Classes/IGListIndexPathResult.html#/c:objc(cs)IGListIndexPathResult(py)moves":{"name":"moves","abstract":"\u003cp\u003eThe moves from an index path in the old collection to an index path in the new collection.\u003c/p\u003e","parent_name":"IGListIndexPathResult"},"Classes/IGListIndexPathResult.html#/c:objc(cs)IGListIndexPathResult(py)hasChanges":{"name":"hasChanges","abstract":"\u003cp\u003eA Read-only boolean that indicates whether the result has any changes or not.","parent_name":"IGListIndexPathResult"},"Classes/IGListIndexPathResult.html#/c:objc(cs)IGListIndexPathResult(im)oldIndexPathForIdentifier:":{"name":"-oldIndexPathForIdentifier:","abstract":"\u003cp\u003eReturns the index path of the object with the specified identifier \u003cem\u003ebefore\u003c/em\u003e the diff.\u003c/p\u003e","parent_name":"IGListIndexPathResult"},"Classes/IGListIndexPathResult.html#/c:objc(cs)IGListIndexPathResult(im)newIndexPathForIdentifier:":{"name":"-newIndexPathForIdentifier:","abstract":"\u003cp\u003eReturns the index path of the object with the specified identifier \u003cem\u003eafter\u003c/em\u003e the diff.\u003c/p\u003e","parent_name":"IGListIndexPathResult"},"Classes/IGListIndexPathResult.html#/c:objc(cs)IGListIndexPathResult(im)resultForBatchUpdates":{"name":"-resultForBatchUpdates","abstract":"\u003cp\u003eCreates a new result object with operations safe for use in \u003ccode\u003eUITableView\u003c/code\u003e and \u003ccode\u003eUICollectionView\u003c/code\u003e batch updates.\u003c/p\u003e","parent_name":"IGListIndexPathResult"},"Classes/IGListBatchUpdateData.html#/c:objc(cs)IGListBatchUpdateData(py)insertSections":{"name":"insertSections","abstract":"\u003cp\u003eSection insert indexes.\u003c/p\u003e","parent_name":"IGListBatchUpdateData"},"Classes/IGListBatchUpdateData.html#/c:objc(cs)IGListBatchUpdateData(py)deleteSections":{"name":"deleteSections","abstract":"\u003cp\u003eSection delete indexes.\u003c/p\u003e","parent_name":"IGListBatchUpdateData"},"Classes/IGListBatchUpdateData.html#/c:objc(cs)IGListBatchUpdateData(py)moveSections":{"name":"moveSections","abstract":"\u003cp\u003eSection moves.\u003c/p\u003e","parent_name":"IGListBatchUpdateData"},"Classes/IGListBatchUpdateData.html#/c:objc(cs)IGListBatchUpdateData(py)insertIndexPaths":{"name":"insertIndexPaths","abstract":"\u003cp\u003eItem insert index paths.\u003c/p\u003e","parent_name":"IGListBatchUpdateData"},"Classes/IGListBatchUpdateData.html#/c:objc(cs)IGListBatchUpdateData(py)deleteIndexPaths":{"name":"deleteIndexPaths","abstract":"\u003cp\u003eItem delete index paths.\u003c/p\u003e","parent_name":"IGListBatchUpdateData"},"Classes/IGListBatchUpdateData.html#/c:objc(cs)IGListBatchUpdateData(py)updateIndexPaths":{"name":"updateIndexPaths","abstract":"\u003cp\u003eItem update index paths.\u003c/p\u003e","parent_name":"IGListBatchUpdateData"},"Classes/IGListBatchUpdateData.html#/c:objc(cs)IGListBatchUpdateData(py)moveIndexPaths":{"name":"moveIndexPaths","abstract":"\u003cp\u003eItem moves.\u003c/p\u003e","parent_name":"IGListBatchUpdateData"},"Classes/IGListBatchUpdateData.html#/c:objc(cs)IGListBatchUpdateData(im)initWithInsertSections:deleteSections:moveSections:insertIndexPaths:deleteIndexPaths:updateIndexPaths:moveIndexPaths:":{"name":"-initWithInsertSections:deleteSections:moveSections:insertIndexPaths:deleteIndexPaths:updateIndexPaths:moveIndexPaths:","abstract":"\u003cp\u003eCreates a new batch update object with section and item operations.\u003c/p\u003e","parent_name":"IGListBatchUpdateData"},"Classes/IGListBatchUpdateData.html":{"name":"IGListBatchUpdateData","abstract":"\u003cp\u003eAn instance of \u003ccode\u003eIGListBatchUpdateData\u003c/code\u003e takes section indexes and item index paths"},"Classes/IGListIndexPathResult.html":{"name":"IGListIndexPathResult","abstract":"\u003cp\u003eA result object returned when diffing with sections.\u003c/p\u003e"},"Classes/IGListIndexSetResult.html":{"name":"IGListIndexSetResult","abstract":"\u003cp\u003eA result object returned when diffing with indexes.\u003c/p\u003e"},"Classes/IGListMoveIndex.html":{"name":"IGListMoveIndex","abstract":"\u003cp\u003eAn object representing a move between indexes.\u003c/p\u003e"},"Classes/IGListMoveIndexPath.html":{"name":"IGListMoveIndexPath","abstract":"\u003cp\u003eAn object representing a move between indexes.\u003c/p\u003e"},"Classes/IGListAdapter.html":{"name":"IGListAdapter","abstract":"\u003cp\u003e\u003ccode\u003eIGListAdapter\u003c/code\u003e objects provide an abstraction for feeds of objects in a \u003ccode\u003eUICollectionView\u003c/code\u003e by breaking each object"},"Classes/IGListAdapterDelegateAnnouncer.html":{"name":"IGListAdapterDelegateAnnouncer","abstract":"\u003cp\u003eUndocumented\u003c/p\u003e"},"Classes/IGListAdapterUpdater.html":{"name":"IGListAdapterUpdater","abstract":"\u003cp\u003eAn \u003ccode\u003eIGListAdapterUpdater\u003c/code\u003e is a concrete type that conforms to \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbProtocols/IGListUpdatingDelegate.html\"\u003eIGListUpdatingDelegate\u003c/a\u003e\u003c/code\u003e."},"Classes/IGListBindingSectionController.html":{"name":"IGListBindingSectionController","abstract":"\u003cp\u003eThis section controller uses a data source to transform its \u0026ldquo;top level\u0026rdquo; object into an array of diffable view models."},"Classes/IGListBindingSingleSectionController.html":{"name":"IGListBindingSingleSectionController","abstract":"\u003cp\u003eSpecial section controller that only contains a single item, and it will apply the view model update during -didUpdateObject: call, usually happened inside -[UICollectionView performBatchUpdates:completion:].\u003c/p\u003e"},"Classes/IGListCollectionView.html":{"name":"IGListCollectionView","abstract":"\u003cp\u003eThis \u003ccode\u003eUICollectionView\u003c/code\u003e subclass allows for partial layout invalidation using \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbClasses/IGListCollectionViewLayout.html\"\u003eIGListCollectionViewLayout\u003c/a\u003e\u003c/code\u003e,"},"Classes/IGListCollectionViewLayout.html":{"name":"IGListCollectionViewLayout","abstract":"\u003cp\u003eThis UICollectionViewLayout subclass is for vertically or horizontally scrolling lists of data with variable widths and"},"Classes/IGListCollectionViewLayoutInvalidationContext.html":{"name":"IGListCollectionViewLayoutInvalidationContext","abstract":"\u003cp\u003eThe default invalidation context class used by IGListCollectionViewLayout.\u003c/p\u003e"},"Classes/IGListGenericSectionController.html":{"name":"IGListGenericSectionController","abstract":"\u003cp\u003eThis class adds a helper layer to \u003ccode\u003eIGListSectionController\u0010\u003c/code\u003e to automatically store a generic object in"},"Classes.html#/c:objc(cs)IGListReloadDataUpdater":{"name":"IGListReloadDataUpdater","abstract":"\u003cp\u003eAn \u003ccode\u003eIGListReloadDataUpdater\u003c/code\u003e is a concrete type that conforms to \u003ccode\u003e\u003ca href=\"36f8f5912051ae747ef441d6511ca4cbProtocols/IGListUpdatingDelegate.html\"\u003eIGListUpdatingDelegate\u003c/a\u003e\u003c/code\u003e."},"Classes/IGListSectionController.html":{"name":"IGListSectionController","abstract":"\u003cp\u003eThe base class for section controllers used in a list. This class is intended to be subclassed.\u003c/p\u003e"},"Classes/IGListSingleSectionController.html":{"name":"IGListSingleSectionController","abstract":"\u003cp\u003eThis section controller is meant to make building simple, single-cell lists easier. By providing the type of cell, a block"},"Classes/IGListTransitionData.html":{"name":"IGListTransitionData","abstract":"\u003cp\u003eContainer object that holds the data needed for an update.\u003c/p\u003e"},"Categories/UIViewController%28IGListAdapter%29.html#/c:objc(cs)UIViewController(im)associatedListAdapters":{"name":"-associatedListAdapters","abstract":"\u003cp\u003eAdapters that have this VC as their \u003ccode\u003eviewController\u003c/code\u003e\u003c/p\u003e","parent_name":"UIViewController(IGListAdapter)"},"Categories/UIViewController%28IGListAdapter%29.html":{"name":"UIViewController(IGListAdapter)","abstract":"\u003cp\u003eUndocumented\u003c/p\u003e"},"best-practices-and-faq.html":{"name":"Best Practices and FAQ"},"generating-your-models-using-remodel.html":{"name":"Generating your models using remodel"},"getting-started.html":{"name":"Getting Started"},"iglistdiffable-and-equality.html":{"name":"IGListDiffable and Equality"},"installation.html":{"name":"Installation"},"migration.html":{"name":"Migration"},"modeling-and-binding.html":{"name":"Modeling and Binding"},"vision.html":{"name":"VISION"},"working-with-core-data.html":{"name":"Working with Core Data"},"working-with-uicollectionview.html":{"name":"Working with UICollectionView"},"Guides.html":{"name":"Guides","abstract":"\u003cp\u003eThe following guides are available globally.\u003c/p\u003e"},"Categories.html":{"name":"Categories","abstract":"\u003cp\u003eThe following categories are available globally.\u003c/p\u003e"},"Classes.html":{"name":"Classes","abstract":"\u003cp\u003eThe following classes are available globally.\u003c/p\u003e"},"Constants.html":{"name":"Constants","abstract":"\u003cp\u003eThe following constants are available globally.\u003c/p\u003e"},"Enums.html":{"name":"Enumerations","abstract":"\u003cp\u003eThe following enumerations are available globally.\u003c/p\u003e"},"Protocols.html":{"name":"Protocols","abstract":"\u003cp\u003eThe following protocols are available globally.\u003c/p\u003e"},"Type%20Definitions.html":{"name":"Type Definitions","abstract":"\u003cp\u003eThe following type definitions are available globally.\u003c/p\u003e"},"Functions.html":{"name":"Functions","abstract":"\u003cp\u003eThe following functions are available globally.\u003c/p\u003e"},"Structs.html":{"name":"Structures","abstract":"\u003cp\u003eThe following structures are available globally.\u003c/p\u003e"}}

---

### Undocumented.Json (`docs/undocumented.json`)

{
  "warnings": [
    {
      "file": "/Users/TiM/Developer/IGListKit/Source/IGListKit/IGListAdapterDelegateAnnouncer.h",
      "line": 18,
      "symbol": "IGListAdapterDelegateAnnouncer",
      "symbol_kind": "sourcekitten.source.lang.objc.decl.class",
      "warning": "undocumented"
    },
    {
      "file": "/Users/TiM/Developer/IGListKit/Source/IGListKit/IGListBindingSingleSectionController.h",
      "line": 29,
      "symbol": "IGListBindingSingleSectionController.-cellClass",
      "symbol_kind": "sourcekitten.source.lang.objc.decl.method.instance",
      "warning": "undocumented"
    },
    {
      "file": "/Users/TiM/Developer/IGListKit/Source/IGListKit/IGListBindingSingleSectionController.h",
      "line": 32,
      "symbol": "IGListBindingSingleSectionController.-configureCell:withViewModel:",
      "symbol_kind": "sourcekitten.source.lang.objc.decl.method.instance",
      "warning": "undocumented"
    },
    {
      "file": "/Users/TiM/Developer/IGListKit/Source/IGListKit/IGListBindingSingleSectionController.h",
      "line": 35,
      "symbol": "IGListBindingSingleSectionController.-sizeForViewModel:",
      "symbol_kind": "sourcekitten.source.lang.objc.decl.method.instance",
      "warning": "undocumented"
    },
    {
      "file": "/Users/TiM/Developer/IGListKit/Source/IGListKit/IGListBindingSingleSectionController.h",
      "line": 38,
      "symbol": "IGListBindingSingleSectionController.-didSelectItemWithCell:",
      "symbol_kind": "sourcekitten.source.lang.objc.decl.method.instance",
      "warning": "undocumented"
    },
    {
      "file": "/Users/TiM/Developer/IGListKit/Source/IGListKit/IGListBindingSingleSectionController.h",
      "line": 41,
      "symbol": "IGListBindingSingleSectionController.-didDeselectItemWithCell:",
      "symbol_kind": "sourcekitten.source.lang.objc.decl.method.instance",
      "warning": "undocumented"
    },
    {
      "file": "/Users/TiM/Developer/IGListKit/Source/IGListKit/IGListBindingSingleSectionController.h",
      "line": 44,
      "symbol": "IGListBindingSingleSectionController.-didHighlightItemWithCell:",
      "symbol_kind": "sourcekitten.source.lang.objc.decl.method.instance",
      "warning": "undocumented"
    },
    {
      "file": "/Users/TiM/Developer/IGListKit/Source/IGListKit/IGListBindingSingleSectionController.h",
      "line": 47,
      "symbol": "IGListBindingSingleSectionController.-didUnhighlightItemWithCell:",
      "symbol_kind": "sourcekitten.source.lang.objc.decl.method.instance",
      "warning": "undocumented"
    },
    {
      "file": "/Users/TiM/Developer/IGListKit/Source/IGListKit/IGListBindingSingleSectionController.h",
      "line": 49,
      "symbol": "IGListBindingSingleSectionController.-isDisplayingCell",
      "symbol_kind": "sourcekitten.source.lang.objc.decl.method.instance",
      "warning": "undocumented"
    },
    {
      "file": "/Users/TiM/Developer/IGListKit/Source/IGListKit/IGListTransitionData.h",
      "line": 27,
      "symbol": "IGListTransitionData.-initFromObjects:toObjects:toSectionControllers:",
      "symbol_kind": "sourcekitten.source.lang.objc.decl.method.instance",
      "warning": "undocumented"
    },
    {
      "file": "/Users/TiM/Developer/IGListKit/Source/IGListKit/IGListTransitionData.h",
      "line": 31,
      "symbol": "IGListTransitionData.-init",
      "symbol_kind": "sourcekitten.source.lang.objc.decl.method.instance",
      "warning": "undocumented"
    },
    {
      "file": "/Users/TiM/Developer/IGListKit/Source/IGListKit/IGListTransitionData.h",
      "line": 32,
      "symbol": "IGListTransitionData.+new",
      "symbol_kind": "sourcekitten.source.lang.objc.decl.method.class",
      "warning": "undocumented"
    },
    {
      "file": "/Users/TiM/Developer/IGListKit/Source/IGListKit/UIViewController+IGListAdapter.h",
      "line": 14,
      "symbol": "UIViewController(IGListAdapter)",
      "symbol_kind": "sourcekitten.source.lang.objc.decl.category",
      "warning": "undocumented"
    }
  ],
  "source_directory": "/Users/TiM/Developer/IGListKit"
}

---

--- METRICS ---
- Files Extracted: 13
- Estimated Token Budget: ~45304 tokens
- Canonical Reference: https://codewiki.google/github.com/Instagram/IGListKit
