IGListKit Documentation

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

13,081 stars Objective-C 13 files ยท ~45,386 tokens #diffing#instagram#ios#objective-c#uicollectionview
RAW Doc

Technical Documentation: Instagram/IGListKit

โ„น๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference

Overview (`README.md`)


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

Main Features
🙅 Never call performBatchUpdates(_:, completion:) or reloadData() again
🏠 Better architecture with reusable cells and components
🔠 Create collections with multiple data types
🔑 Decoupled diffing algorithm
✅ Fully unit tested
🔍 Customize your diffing behavior for your models
📱 Simply UICollectionView at its core
🚀 Extendable API
🐦 Written in Objective-C with full Swift interop support

IGListKit is built and maintained with ❤️ by Instagram engineering.
We use the open source version main branch in the Instagram app.

Multilingual translation

Chinese README

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. Add the following to your Podfile:

ruby
pod 'IGListKit', '~> 5.2.0'

Carthage

For Carthage, add the following to your Cartfile:

ogdl
github "Instagram/IGListKit" ~> 5.2.0

Swift Package Manager

For Swift Package Manager:

text
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.

Getting Started

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

Documentation

You can find the docs here. Documentation is generated with jazzy and hosted on GitHub-Pages.

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 doc.

Contributing

Please see the CONTRIBUTING 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 that are great for beginners to jump in on and start contributing.

License

IGListKit is MIT-licensed.

The files in the /Examples/ directory are licensed under a separate license as specified in each file. Documentation is licensed CC-BY-4.0.

Copyright ยฉ Meta Platforms, Inc • Terms of Use • Privacy Policy


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: on the object you receive in -didUpdateToObject: in your section controllers.
    This makes it easy to track down easily-overlooked mistakes in your IGListAdapaterDataSource 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 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 to make upgrading easier.

How do you implement separators between cells?

See discussion in #329

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

See discussion in #316

The documentation and examples have `` 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. If you need to, you can install from the main branch.

Does `IGListKit` work with...?

Yes.

Does `IGListKit` work with `UITableView`?

No, but you can install the diffing subspec via CocoaPods.

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.

How can I manage cell selection and deselection?

See discussion at #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: 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, 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 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 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.

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.

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 of this.

How do I make my cells diff and animate?

Use IGListBindingSectionController 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 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, 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 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:
text
// 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:

text
# 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:

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

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

Documentation

Please see the main remodel repository for additional documentation


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

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

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. 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 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.

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, 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.

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.

"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 instead of the layout
  • Set minimumInteritemSpacing on your section controllers instead of the layout
  • Return the size of your cells in sizeForItemAtIndex: 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.

`IGListDiffable` Conformance

If you relied on the default NSObject 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 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. 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 classes 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.

Comment implementation

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.

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.

View model implementations

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.

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. 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 55pts 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.

"cellForViewModel:" implementation

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!

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

    ListBindable implementations

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
  }

}

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!

Wrapping up

If you got stuck at all, or just want to play around with the example, you can find the finished project here 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!


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 UICollectionViewLayouts
  • 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 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 NSManagedObjects 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, #461, #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. 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 and IGListKit.

Background

Early versions of IGListKit (2.x and prior) shipped with a subclass of UICollectionView called IGListCollectionView. 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 for a number of reasons.

For further discussion see #240 and #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. You should also avoid setting the delegate and 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 was introduced. At Instagram, enabling this feature substantially degraded scrolling performance. We recommend setting 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 ---