### User Instance Example Source: https://github.com/instagram/iglistkit/blob/main/Guides/Getting Started.md An example of creating a User instance. ```swift let shayne = User(primaryKey: 2, name: "Shayne") ``` -------------------------------- ### User Model Example Source: https://github.com/instagram/iglistkit/blob/main/docs/getting-started.html An example of a User model before conforming to ListDiffable. ```swift class User { let primaryKey: Int let name: String // implementation, etc } ``` -------------------------------- ### User Model Example Source: https://github.com/instagram/iglistkit/blob/main/Guides/Getting Started.md An example of a User model that will be used to demonstrate diffing. ```swift class User { let primaryKey: Int let name: String // implementation, etc } ``` -------------------------------- ### UICollectionView and IGListAdapter Setup Source: https://github.com/instagram/iglistkit/blob/main/Guides/Getting Started.md Setting up 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 ``` -------------------------------- ### User Model Conforming to ListDiffable Source: https://github.com/instagram/iglistkit/blob/main/docs/getting-started.html Example of conforming a User model to the ListDiffable 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 } } ``` -------------------------------- ### Initializing ListAdapter with Working Range Source: https://github.com/instagram/iglistkit/blob/main/Guides/Getting Started.md Example of initializing ListAdapter with a working range size. ```swift let adapter = ListAdapter(updater: ListAdapterUpdater(), viewController: self, workingRangeSize: 1) // 1 before/after visible objects ``` -------------------------------- ### Updated User Instance Example Source: https://github.com/instagram/iglistkit/blob/main/Guides/Getting Started.md An example of an updated User instance with the same primary key but a different name. ```swift let ann = User(primaryKey: 2, name: "Ann") ``` -------------------------------- ### Using ListDiff Outside of IGListAdapter Source: https://github.com/instagram/iglistkit/blob/main/docs/getting-started.html Demonstrates using the ListDiff algorithm directly. ```swift let result = ListDiff(oldArray: oldUsers, newArray: newUsers, .equality) ``` -------------------------------- ### Install with Carthage Source: https://github.com/instagram/iglistkit/blob/main/Guides/Installation.md Add this to your Cartfile if using Carthage. ```ogdl github "Instagram/IGListKit" ~> 4.0 ``` -------------------------------- ### IGListAdapter Data Source Implementation Source: https://github.com/instagram/iglistkit/blob/main/Guides/Getting Started.md Implementing the data source methods for IGListAdapter. ```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 } ``` -------------------------------- ### LabelSectionController Example Source: https://github.com/instagram/iglistkit/blob/main/Guides/Getting Started.md An example of a 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) } } ``` -------------------------------- ### Using ListDiff Outside of IGListAdapter Source: https://github.com/instagram/iglistkit/blob/main/Guides/Getting Started.md Demonstrates how to use the diffing algorithm independently of IGListAdapter. ```swift let result = ListDiff(oldArray: oldUsers, newArray: newUsers, .equality) ``` -------------------------------- ### Import IGListKit Source: https://github.com/instagram/iglistkit/blob/main/Guides/Installation.md Import statement for both full library and diffing components. ```swift import IGListKit ``` -------------------------------- ### CocoaPods Installation Source: https://github.com/instagram/iglistkit/blob/main/README.md The preferred installation method is with CocoaPods. Add the following to your Podfile: ```ruby pod 'IGListKit', '~> 5.2.0' ``` -------------------------------- ### Carthage Installation Source: https://github.com/instagram/iglistkit/blob/main/README.md For Carthage, add the following to your Cartfile: ```ogdl github "Instagram/IGListKit" ~> 5.2.0 ``` -------------------------------- ### Install from Main Branch with CocoaPods Source: https://github.com/instagram/iglistkit/blob/main/Guides/Installation.md Use the latest version from the main branch, which is stable and reliable. ```ruby pod 'IGListKit', :git => 'https://github.com/Instagram/IGListKit.git', :branch => 'main' ``` -------------------------------- ### Install Diffing Subspec with CocoaPods Source: https://github.com/instagram/iglistkit/blob/main/Guides/Installation.md Use this if you only need the diffing components of IGListKit. ```ruby pod 'IGListKit/Diffing', '~> 4.0' ``` -------------------------------- ### Wrapper Model Example Source: https://github.com/instagram/iglistkit/blob/main/Guides/Best Practices and FAQ.md An example of creating a wrapper model for use in section controllers. ```swift class WeatherSectionModel { let location: Location let forecast: Forecast let conditions: Conditions } ``` -------------------------------- ### Install Latest Release with CocoaPods Source: https://github.com/instagram/iglistkit/blob/main/Guides/Installation.md Add this to your Podfile to use the latest release of IGListKit. ```ruby pod 'IGListKit', '~> 4.0' ``` -------------------------------- ### Connecting Data Source to Adapter Source: https://github.com/instagram/iglistkit/blob/main/Guides/Getting Started.md Connecting the data source to the IGListAdapter by setting its dataSource property. ```swift adapter.dataSource = self ``` -------------------------------- ### IGListDiffable Conformance Source: https://github.com/instagram/iglistkit/blob/main/Guides/Getting Started.md Implementing the ListDiffable protocol for the User model to enable custom diffing. ```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 } } ``` -------------------------------- ### Wrapper Model Example Source: https://github.com/instagram/iglistkit/blob/main/docs/best-practices-and-faq.html Example of creating a wrapper model for use in section controllers and making it diffable. ```swift class WeatherSectionModel { let location: Location let forecast: Forecast let conditions: Conditions } 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 } } ``` -------------------------------- ### Diffable Object Example Source: https://github.com/instagram/iglistkit/blob/main/docs/modeling-and-binding.html Example of implementing diffable object protocol for a post. ```swift func diffIdentifier() -> NSObjectProtocol { return (username + timestamp) as NSObjectProtocol } // 2 func isEqual(toDiffableObject object: ListDiffable?) -> Bool { return true } ``` -------------------------------- ### User NSManagedObject Source: https://github.com/instagram/iglistkit/blob/main/Guides/Working with Core Data.md Example of a User NSManagedObject with properties. ```swift extension User { @NSManaged var firstName: String @NSManaged var lastName: String @NSManaged var address: String @NSManaged var someVariableNotNeededInUI: String } ``` -------------------------------- ### Swift Batch Update Example Source: https://github.com/instagram/iglistkit/blob/main/docs/migration.html Demonstrates how to perform item mutations within a batch update block in 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]) }) ``` -------------------------------- ### Dynamic Array Example Source: https://github.com/instagram/iglistkit/blob/main/Guides/Best Practices and FAQ.md An example of a model that owns an array to power numberOfItems, demonstrating how to check for array changes for diffing. ```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 } } ``` -------------------------------- ### PostSectionController.swift Source: https://github.com/instagram/iglistkit/blob/main/Guides/Modeling and Binding.md Initial setup for PostSectionController, subclassing ListBindingSectionController and setting the data source. ```swift final class PostSectionController: ListBindingSectionController, ListBindingSectionControllerDataSource { override init() { super.init() dataSource = self } } ``` -------------------------------- ### Objective-C Batch Update Example Source: https://github.com/instagram/iglistkit/blob/main/docs/migration.html Demonstrates how to perform item mutations within a batch update block in Objective-C. ```objective-c // OLD self.expanded = YES; [self.collectionContext insertInSectionController:self atIndexes:[NSIndexSet indexSetWithIndex:]]; // NEW [self.collectionContext performBatchAnimated:YES updates:^(id batchContext) { self.expanded = YES; [batchContext insertInSectionController:self atIndexes:[NSIndexSet indexSetWithIndex:1]]; } completion:nil]; ``` -------------------------------- ### ListBindable Implementations Source: https://github.com/instagram/iglistkit/blob/main/docs/modeling-and-binding.html Example Swift code demonstrating ListBindable implementations for ActionCell, UserCell, and CommentCell. ```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 } } ``` -------------------------------- ### IGListDiffable bare minimum Source: https://github.com/instagram/iglistkit/blob/main/Guides/IGListDiffable and Equality.md 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)diffIdentifier { return self; } - (BOOL)isEqualToDiffableObject:(id)object { return [self isEqual:object]; } ``` -------------------------------- ### PersonModel.value example Source: https://github.com/instagram/iglistkit/blob/main/Guides/Generating your models using remodel.md Example of a .value file defining a PersonModel that includes IGListDiffable. ```remodel # PersonModel.value PersonModel includes(IGListDiffable) { NSString *firstName NSString *lastName %diffIdentifier NSString *uniqueId } ``` -------------------------------- ### UserCell Implementation Source: https://github.com/instagram/iglistkit/blob/main/Guides/Modeling and Binding.md Example of a UserCell conforming to ListBindable to bind a UserViewModel. ```swift 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 } } ``` -------------------------------- ### Post Model Implementation Source: https://github.com/instagram/iglistkit/blob/main/docs/modeling-and-binding.html Example of a Post model conforming to ListDiffable, holding data for a list item. ```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 } } // MARK: ListDiffable func diffIdentifier() -> NSObjectProtocol { // 1 ``` -------------------------------- ### Updating listAdapter delegate method Source: https://github.com/instagram/iglistkit/blob/main/Guides/Modeling and Binding.md Example of updating the listAdapter delegate method to return PostSectionController. ```swift func listAdapter( _ listAdapter: ListAdapter, sectionControllerFor object: Any ) -> ListSectionController { return PostSectionController() } ``` -------------------------------- ### User model equality methods Source: https://github.com/instagram/iglistkit/blob/main/Guides/IGListDiffable and Equality.md Example implementation of equality methods for a User model with identifier, name, and posts properties. ```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 ``` -------------------------------- ### IGListDiffable bare minimum Source: https://github.com/instagram/iglistkit/blob/main/docs/iglistdiffable-and-equality.html The quickest way to get started with diffable models is to use the object itself as the identifier, and use the superclass’s -[NSObject isEqual:] implementation for equality. ```objective-c - (id)diffIdentifier { return self; } - (BOOL)isEqualToDiffableObject:(id)object { return [self isEqual:object]; } ``` -------------------------------- ### ActionCell Implementation Source: https://github.com/instagram/iglistkit/blob/main/Guides/Modeling and Binding.md Example of an ActionCell conforming to ListBindable to bind an ActionViewModel. ```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)" } } ``` -------------------------------- ### IGListDiffable Conformance (Swift) Source: https://github.com/instagram/iglistkit/blob/main/Guides/Migration.md Example of conforming to IGListDiffable in Swift to maintain previous behavior. ```swift import IGListKit extension MyModel: ListDiffable { func diffIdentifier() -> NSObjectProtocol { return self } func isEqual(toDiffableObject object: ListDiffable?) -> Bool { return isEqual(object) } } ``` -------------------------------- ### Displaying in the View Controller Source: https://github.com/instagram/iglistkit/blob/main/docs/modeling-and-binding.html Example Swift code to add a Post object to the data array in a ViewController. ```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"), ] )) ``` -------------------------------- ### Swift Item Mutations Source: https://github.com/instagram/iglistkit/blob/main/Guides/Migration.md Example of how to perform item mutations within a batch block in 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]) }) ``` -------------------------------- ### CommentCell Implementation Source: https://github.com/instagram/iglistkit/blob/main/Guides/Modeling and Binding.md Example of a CommentCell conforming to ListBindable to bind a Comment object. ```swift 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 } } ``` -------------------------------- ### ImageCell Implementation Source: https://github.com/instagram/iglistkit/blob/main/Guides/Modeling and Binding.md Example of an ImageCell conforming to ListBindable to bind an ImageViewModel. ```swift import UIKit import SDWebImage import IGListKit final class ImageCell: UICollectionViewCell, ListBindable { @IBOutlet weak var imageView: UIImageView! // MARK: ListBindable func bindViewModel(_ viewModel: Any) { guard let viewModel = viewModel as? ImageViewModel else { return } imageView.sd_setImage(with: viewModel.url) } } ``` -------------------------------- ### Adding Data to ViewController Source: https://github.com/instagram/iglistkit/blob/main/Guides/Modeling and Binding.md Example of adding a Post object to the data array in ViewController.swift. ```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"), ] )) ``` -------------------------------- ### Registering the iglistdiffable plugin Source: https://github.com/instagram/iglistkit/blob/main/Guides/Generating your models using remodel.md Example of how to register the 'iglistdiffable' plugin in the remodel configuration file. ```typescript // 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' ) ``` -------------------------------- ### Objective-C Item Mutations Source: https://github.com/instagram/iglistkit/blob/main/Guides/Migration.md Example of how to perform item mutations within a batch block in Objective-C. ```objc // OLD self.expanded = YES; [self.collectionContext insertInSectionController:self atIndexes:[NSIndexSet indexSetWithIndex:]]; // NEW [self.collectionContext performBatchAnimated:YES updates:^(id batchContext) { self.expanded = YES; [batchContext insertInSectionController:self atIndexes:[NSIndexSet indexSetWithIndex:1]]; } completion:nil]; ``` -------------------------------- ### Customized Initial Layout Attributes Source: https://github.com/instagram/iglistkit/blob/main/docs/Protocols/IGListCollectionViewDelegateLayout.html Asks the delegate to customize and return the starting layout information for an item being inserted into the collection view. ```objc - (UICollectionViewLayoutAttributes *)collectionView: (UICollectionView *)collectionView layout:(UICollectionViewLayout *) collectionViewLayout customizedInitialLayoutAttributes: (UICollectionViewLayoutAttributes *)attributes atIndexPath:(NSIndexPath *)indexPath; ``` ```swift func collectionView(_ collectionView: UICollectionView!, layout collectionViewLayout: UICollectionViewLayout!, customizedInitialLayoutAttributes attributes: UICollectionViewLayoutAttributes!, at indexPath: IndexPath!) -> UICollectionViewLayoutAttributes! ``` -------------------------------- ### UserProvider class for fetching Core Data objects Source: https://github.com/instagram/iglistkit/blob/main/Guides/Working with Core Data.md Example of a Provider class using NSFetchedResultsController to fetch Core Data objects and track updates. ```swift final class UserProvider: NSObject { private lazy var userFetchResultController: NSFetchedResultsController = { let fetchRequest: NSFetchRequest = 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)") } } } ``` -------------------------------- ### IGListDiffable Conformance (Objective-C) Source: https://github.com/instagram/iglistkit/blob/main/Guides/Migration.md Example of conforming to IGListDiffable in Objective-C to maintain previous behavior. ```objc #import // Header @interface MyModel // Implementation - (id)diffIdentifier { return self; } - (BOOL)isEqualToDiffableObject:(id)object { return [self isEqual:object]; } ``` -------------------------------- ### Objective-C Equality Check Source: https://github.com/instagram/iglistkit/blob/main/docs/Classes/IGListBindingSectionController.html Example of how to implement -isEqualToDiffableObject: in Objective-C for IGListBindingSectionController. ```Objective-C - (BOOL)isEqualToDiffableObject:(id)object { return YES; } ``` -------------------------------- ### Customized Initial Layout Attributes Source: https://github.com/instagram/iglistkit/blob/main/docs/Protocols/IGListTransitionDelegate.html Asks the delegate to customize and return the starting layout information for an item being inserted into the collection view. ```objc - (UICollectionViewLayoutAttributes *)listAdapter:(IGListAdapter *)listAdapter customizedInitialLayoutAttributes: (UICollectionViewLayoutAttributes *)attributes sectionController: (IGListSectionController *)sectionController atIndex:(NSInteger)index; ``` ```swift func listAdapter(_ listAdapter: Any!, customizedInitialLayoutAttributes attributes: Any!, sectionController: Any!, atIndex index: Any!) -> Any! ``` -------------------------------- ### Swift Equality Check Source: https://github.com/instagram/iglistkit/blob/main/docs/Classes/IGListBindingSectionController.html Example of how to implement isEqual(toDiffableObject:) in Swift for ListBindingSectionController. ```Swift func isEqual(toDiffableObject object: IGListDiffable?) -> Bool { return true } ``` -------------------------------- ### Swift Package Manager Installation Source: https://github.com/instagram/iglistkit/blob/main/README.md For Swift Package Manager, you can integrate using Xcode by going to File -> Swift Packages -> Add Package Dependency and entering the package URL: https://github.com/Instagram/IGListKit, then selecting the latest release. ```swift https://github.com/Instagram/IGListKit ``` -------------------------------- ### UserProvider with NSFetchedResultsController Source: https://github.com/instagram/iglistkit/blob/main/docs/working-with-core-data.html An example of a UserProvider class using NSFetchedResultsController to fetch Core Data objects and track updates. ```swift final class UserProvider: NSObject { private lazy var userFetchResultController: NSFetchedResultsController = { let fetchRequest: NSFetchRequest = 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)") } } } ``` -------------------------------- ### Updating listAdapter delegate method Source: https://github.com/instagram/iglistkit/blob/main/docs/modeling-and-binding.html Example Swift code to update the listAdapter delegate method to return a PostSectionController. ```swift func listAdapter( _ listAdapter: ListAdapter, sectionControllerFor object: Any ) -> ListSectionController { return PostSectionController() } ``` -------------------------------- ### User Class Implementation Source: https://github.com/instagram/iglistkit/blob/main/docs/iglistdiffable-and-equality.html Example implementation of the User class conforming to IGListDiffable, including diffIdentifier, isEqualToDiffableObject, and isEqual methods. ```Objective-C @interface User // properties... @end @implementation User - (id)diffIdentifier { return @(self.identifier); } - (BOOL)isEqualToDiffableObject:(id)object { return [self isEqual:object]; } - (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 ``` -------------------------------- ### Swift didUpdateToObject Source: https://github.com/instagram/iglistkit/blob/main/Guides/Best Practices and FAQ.md Example of adding a precondition to check the object type in didUpdateToObject for Swift. ```swift // Swift func didUpdate(to object: Any) { precondition(object is MyModelClass) myModel = object as! MyModelClass } ``` -------------------------------- ### IGListDiffable Conformance - Swift Source: https://github.com/instagram/iglistkit/blob/main/docs/migration.html Example of conforming a model to the ListDiffable protocol in Swift, replicating 1.0 behavior. ```swift import IGListKit extension MyModel: ListDiffable { func diffIdentifier() -> NSObjectProtocol { return self } func isEqual(toDiffableObject object: ListDiffable?) -> Bool { return isEqual(object) } } ``` -------------------------------- ### Objective-C didUpdateToObject Source: https://github.com/instagram/iglistkit/blob/main/Guides/Best Practices and FAQ.md Example of adding an assert to check the object type in didUpdateToObject for Objective-C. ```objective-c // Objective-C - (void)didUpdateToObject:(id)object { NSParameterAssert([object isKindOfClass:[MyModelClass class]]); _myModel = object; } ``` -------------------------------- ### Swift Package Manager Installation (Xcode) Source: https://github.com/instagram/iglistkit/blob/main/docs/index.html Integrate IGListKit using Swift Package Manager via Xcode by adding the package dependency. ```swift File -> Swift Packages -> Add Package Dependency Enter package URL: https://github.com/Instagram/IGListKit, and select the latest release. ``` -------------------------------- ### listAdapter:didEndDisplayingObject:cell:atIndexPath: Source: https://github.com/instagram/iglistkit/blob/main/docs/Protocols/IGListAdapterDelegate.html Notifies the delegate that a list object is no longer being displayed. This method is distinct from didEndDisplayingObject:atIndex because this method gets called whenever a cell ends display on screen as opposed to didEndDisplayingObject:atIndex which only gets called once when the section fully ends display. ```objc - (void)listAdapter:(nonnull IGListAdapter *)listAdapter didEndDisplayingObject:(nonnull id)object cell:(nonnull UICollectionViewCell *)cell atIndexPath:(nonnull NSIndexPath *)indexPath; ``` ```swift func listAdapter(_ listAdapter: IGListAdapter, didEndDisplaying object: Any, cell: UICollectionViewCell, at indexPath: IndexPath) ``` -------------------------------- ### PostSectionController ActionViewModel Initialization Source: https://github.com/instagram/iglistkit/blob/main/Guides/Modeling and Binding.md Initializes ActionViewModel with localLikes if available, otherwise with object.likes. ```swift ActionViewModel(likes: localLikes ?? object.likes) ``` -------------------------------- ### ImageViewModel and ActionViewModel Implementations Source: https://github.com/instagram/iglistkit/blob/main/docs/modeling-and-binding.html Implementations for ImageViewModel and ActionViewModel. ```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 } } ``` -------------------------------- ### Initializer with Nib Name Source: https://github.com/instagram/iglistkit/blob/main/docs/Classes/IGListSingleSectionController.html Initializes a new section controller using a nib file for the cell. ```Objective-C - (nonnull instancetype)initWithNibName:(nullable NSString *)nibName bundle:(nullable NSBundle *)bundle configureBlock: (nonnull IGListSingleSectionCellConfigureBlock)configureBlock sizeBlock:(nonnull IGListSingleSectionCellSizeBlock)sizeBlock; ``` ```Swift init(nibName: String, bundle: Bundle?, configureBlock: @escaping ListSingleSectionCellConfigureBlock, sizeBlock: @escaping ListSingleSectionCellSizeBlock) ``` -------------------------------- ### ImageViewModel and ActionViewModel Implementations Source: https://github.com/instagram/iglistkit/blob/main/Guides/Modeling and Binding.md Implementations for ImageViewModel and ActionViewModel, conforming to ListDiffable. ```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 } } ``` -------------------------------- ### Swift oldIndexPathForIdentifier: Method Source: https://github.com/instagram/iglistkit/blob/main/docs/Classes/IGListIndexPathResult.html Swift method to get the old index path for an identifier. ```swift func oldIndexPath(forIdentifier identifier: any NSObjectProtocol) -> IndexPath? ``` -------------------------------- ### initWithUpdater:viewController:workingRangeSize: Source: https://github.com/instagram/iglistkit/blob/main/docs/Classes/IGListAdapter.html Initializes a new IGListAdapter object. ```Objective-C - (nonnull instancetype) initWithUpdater:(nonnull id)updater viewController:(nullable UIViewController *)viewController workingRangeSize:(NSInteger)workingRangeSize; ``` ```Swift init(updater: any IGListUpdatingDelegate, viewController: UIViewController?, workingRangeSize: Int) ``` -------------------------------- ### Objective-C oldIndexPathForIdentifier: Method Source: https://github.com/instagram/iglistkit/blob/main/docs/Classes/IGListIndexPathResult.html Objective-C method to get the old index path for an identifier. ```objc - (nullable NSIndexPath *)oldIndexPathForIdentifier: (nonnull id)identifier; ``` -------------------------------- ### IGListTransitionData init Objective-C Source: https://github.com/instagram/iglistkit/blob/main/docs/Classes/IGListTransitionData.html Unavailable Objective-C initializer for IGListTransitionData. ```objc - (instancetype)init NS_UNAVAILABLE; ``` -------------------------------- ### Size for each view model Source: https://github.com/instagram/iglistkit/blob/main/Guides/Modeling and Binding.md Implementation of the sectionController(_:sizeForViewModel:at:) method to determine the appropriate size for each view model. ```swift func sectionController( _ sectionController: ListBindingSectionController, 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) } ``` -------------------------------- ### Swift Method Signature Source: https://github.com/instagram/iglistkit/blob/main/docs/Protocols/IGListCollectionViewDelegateLayout.html The Swift method signature for customizing layout attributes. ```Swift func collectionView(_ collectionView: UICollectionView!, layout collectionViewLayout: UICollectionViewLayout!, customizedFinalLayoutAttributes attributes: UICollectionViewLayoutAttributes!, at indexPath: IndexPath!) -> UICollectionViewLayoutAttributes! ``` -------------------------------- ### configureCell:withViewModel: Declaration Source: https://github.com/instagram/iglistkit/blob/main/docs/Classes/IGListBindingSingleSectionController.html Declaration for the configureCell:withViewModel: method in Objective-C and Swift. ```Objective-C - (void)configureCell:(Cell)cell withViewModel:(ViewModel)viewModel; ``` ```Swift func configureCell(_ cell: Cell, withViewModel viewModel: ViewModel) ``` -------------------------------- ### Objective-C initWithNibName:bundle:configureBlock:sizeBlock: Source: https://github.com/instagram/iglistkit/blob/main/docs/Classes/IGListSingleSectionController.html Creates a new section controller for a given nib name and bundle that will always have only one cell when present in a list. ```objc - (nonnull instancetype) initWithNibName:(nonnull NSString *)nibName ``` -------------------------------- ### Declaration of emptyView(for:) Source: https://github.com/instagram/iglistkit/blob/main/docs/Protocols/IGListAdapterDataSource.html This snippet shows the Objective-C and Swift declarations for the emptyView(for:) method, which is called by the list adapter to get a background view. ```Objective-C - (nullable UIView *)emptyViewForListAdapter: (nonnull IGListAdapter *)listAdapter; ``` ```Swift func emptyView(for listAdapter: IGListAdapter) -> UIView? ``` -------------------------------- ### Swift Initialization Source: https://github.com/instagram/iglistkit/blob/main/docs/Classes/IGListSingleSectionController.html Creates a new section controller for a given cell type that will always have only one cell when present in a list. ```swift class ListSingleSectionController : ListSectionController ``` -------------------------------- ### Type Checking in didUpdateToObject Source: https://github.com/instagram/iglistkit/blob/main/docs/best-practices-and-faq.html Example of adding an assert to check the object type in `didUpdateToObject` within a section controller to catch easily-overlooked mistakes in the `IGListAdapterDataSource` implementation. ```Objective-C - (void)didUpdateToObject:(id)object { NSParameterAssert([object isKindOfClass:[MyModelClass class]]); _myModel = object; } ``` ```Swift func didUpdate(to object: Any) { precondition(object is MyModelClass) myModel = object as! MyModelClass } ``` -------------------------------- ### Wrapper Model Diffable Conformance Source: https://github.com/instagram/iglistkit/blob/main/Guides/Best Practices and FAQ.md Making a wrapper model diffable by conforming to ListDiffable. ```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 } } ``` -------------------------------- ### initWithStickyHeaders:scrollDirection:topContentInset:stretchToEdge: Source: https://github.com/instagram/iglistkit/blob/main/docs/Classes/IGListCollectionViewLayout.html Create and return a new collection view layout. ```Objective-C - (nonnull instancetype) initWithStickyHeaders:(BOOL)stickyHeaders scrollDirection:(UICollectionViewScrollDirection)scrollDirection topContentInset:(CGFloat)topContentInset stretchToEdge:(BOOL)stretchToEdge; ``` ```Swift init(stickyHeaders: Bool, scrollDirection: UICollectionView.ScrollDirection, topContentInset: CGFloat, stretchToEdge: Bool) ``` -------------------------------- ### offsetForFirstVisibleItemWithScrollDirection: Source: https://github.com/instagram/iglistkit/blob/main/docs/Classes/IGListAdapter.html Gets the scroll offset of the first visible cell scrolled into in the collection view. This refers to the cell currently at the top/left (0, 0) of the collection view’s frame, inset by the collection view’s contentInset top or left value if defined. ```Objective-C - (CGFloat)offsetForFirstVisibleItemWithScrollDirection: (UICollectionViewScrollDirection)scrollDirection; ``` ```Swift func offsetForFirstVisibleItem(with scrollDirection: UICollectionView.ScrollDirection) -> CGFloat ``` -------------------------------- ### Using both IGListDiffable and -isEqual: Source: https://github.com/instagram/iglistkit/blob/main/Guides/IGListDiffable and Equality.md Making objects work universally with Objective-C containers and IGListKit by implementing -isEqual: and -hash. ```objc @interface User // properties... @end @implementation User - (id)diffIdentifier { return @(self.identifier); } - (BOOL)isEqualToDiffableObject:(id)object { return [self isEqual:object]; } @end ``` -------------------------------- ### UserViewModel Implementation Source: https://github.com/instagram/iglistkit/blob/main/docs/modeling-and-binding.html Implementation of the UserViewModel for the UserCell. ```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 } } ``` -------------------------------- ### Comment Model Implementation Source: https://github.com/instagram/iglistkit/blob/main/Guides/Modeling and Binding.md Implementation of the Comment model conforming to ListDiffable. ```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 } } ``` -------------------------------- ### supportedElementKinds Method Source: https://github.com/instagram/iglistkit/blob/main/docs/Protocols/IGListSupplementaryViewSource.html Asks the SupplementaryViewSource for an array of supported element kinds. ```objc - (nonnull NSArray *)supportedElementKinds; ``` ```swift func supportedElementKinds() -> [String] ``` -------------------------------- ### Initializer with Storyboard Cell Identifier Source: https://github.com/instagram/iglistkit/blob/main/docs/Classes/IGListSingleSectionController.html Creates a new section controller for a given storyboard cell identifier. ```Objective-C - (nonnull instancetype) initWithStoryboardCellIdentifier:(nonnull NSString *)identifier configureBlock: (nonnull IGListSingleSectionCellConfigureBlock) configureBlock sizeBlock:(nonnull IGListSingleSectionCellSizeBlock) sizeBlock; ``` ```Swift init(storyboardCellIdentifier identifier: String, configureBlock: @escaping ListSingleSectionCellConfigureBlock, sizeBlock: @escaping ListSingleSectionCellSizeBlock) ``` -------------------------------- ### Comment Model Implementation Source: https://github.com/instagram/iglistkit/blob/main/docs/modeling-and-binding.html Implementation of the Comment model conforming to ListDiffable. ```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 } } ``` -------------------------------- ### initWithStickyHeaders:topContentInset:stretchToEdge: Source: https://github.com/instagram/iglistkit/blob/main/docs/Classes/IGListCollectionViewLayout.html Create and return a new vertically scrolling collection view layout. ```Objective-C - (nonnull instancetype)initWithStickyHeaders:(BOOL)stickyHeaders topContentInset:(CGFloat)topContentInset stretchToEdge:(BOOL)stretchToEdge; ``` ```Swift convenience init(stickyHeaders: Bool, topContentInset: CGFloat, stretchToEdge: Bool) ``` -------------------------------- ### initWithUpdater:viewController: Source: https://github.com/instagram/iglistkit/blob/main/docs/Classes/IGListAdapter.html Initializes a new IGListAdapter object with a working range of 0. ```Objective-C - (nonnull instancetype) initWithUpdater:(nonnull id)updater viewController:(nullable UIViewController *)viewController; ``` ```Swift convenience init(updater: any IGListUpdatingDelegate, viewController: UIViewController?) ``` -------------------------------- ### Declaration Source: https://github.com/instagram/iglistkit/blob/main/docs/Protocols/IGListBindingSectionControllerDataSource.html The declaration of the sizeForViewModel method in both Objective-C and Swift. ```objective-c - (CGSize)sectionController: (nonnull IGListBindingSectionController *)sectionController sizeForViewModel:(nonnull id)viewModel atIndex:(NSInteger)index; ``` ```swift func sectionController(_ sectionController: IGListBindingSectionController, sizeForViewModel viewModel: Any, at index: Int) -> CGSize ``` -------------------------------- ### Objective-C Initialization Source: https://github.com/instagram/iglistkit/blob/main/docs/Classes/IGListSingleSectionController.html Creates a new section controller for a given cell type that will always have only one cell when present in a list. ```objc @interface IGListSingleSectionController : IGListSectionController ``` -------------------------------- ### IGListTransitionData initFromObjects:toObjects:toSectionControllers: Swift Source: https://github.com/instagram/iglistkit/blob/main/docs/Classes/IGListTransitionData.html Swift initializer for ListTransitionData. ```swift init(from fromObjects: [Any], to toObjects: [Any], to toSectionControllers: [IGListSectionController]) ``` -------------------------------- ### PostSectionController ActionCellDelegate Implementation Source: https://github.com/instagram/iglistkit/blob/main/Guides/Modeling and Binding.md Provides an empty implementation for the ActionCellDelegate protocol in PostSectionController. ```swift final class PostSectionController: ListBindingSectionController, ListBindingSectionControllerDataSource, ActionCellDelegate { //... // MARK: ActionCellDelegate func didTapHeart(cell: ActionCell) { print("like") } } ``` -------------------------------- ### ListDiffable Implementation for Post Source: https://github.com/instagram/iglistkit/blob/main/Guides/Modeling and Binding.md Implements the ListDiffable protocol for the Post model, providing a unique identifier and equality check. ```swift // MARK: ListDiffable func diffIdentifier() -> NSObjectProtocol { // 1 return (username + timestamp) as NSObjectProtocol } // 2 func isEqual(toDiffableObject object: ListDiffable?) -> Bool { return true } ``` -------------------------------- ### Swift Class Source: https://github.com/instagram/iglistkit/blob/main/docs/Classes/IGListBindingSingleSectionController.html Swift class definition for IGListBindingSingleSectionController. ```swift class ListBindingSingleSectionController : ListSectionController where ViewModel : ListDiffable, Cell : UICollectionViewCell ``` -------------------------------- ### UserViewModel Implementation Source: https://github.com/instagram/iglistkit/blob/main/Guides/Modeling and Binding.md Implementation of the UserViewModel for a UserCell, conforming to ListDiffable. ```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 } } ``` -------------------------------- ### Generated PersonModel.m file Source: https://github.com/instagram/iglistkit/blob/main/docs/generating-your-models-using-remodel.html The Objective-C implementation file for PersonModel, including initializers, diffIdentifier, equality, copyWithZone, description, and hash methods. ```objective-c @implementation PersonModel - (instancetype)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName uniqueId:(NSString *)uniqueId { if ((self = [super init])) { _firstName = [firstName copy]; _lastName = [lastName copy]; _uniqueId = [uniqueId copy]; } return self; } - (id)diffIdentifier { return _uniqueId; } - (BOOL)isEqualToDiffableObject:(nullable id)object { return [self isEqual:object]; } - (BOOL)isEqual:(PersonModel *)object { if (self == object) { return YES; } else if (self == nil || object == nil || ![object isKindOfClass:[self class]]) { return NO; } return (_firstName == object->_firstName ? YES : [_firstName isEqual:object->_firstName]) && (_lastName == object->_lastName ? YES : [_lastName isEqual:object->_lastName]) && (_uniqueId == object->_uniqueId ? YES : [_uniqueId isEqual:object->_uniqueId]); } - (id)copyWithZone:(nullable NSZone *)zone { return self; } - (NSString *)description { return [NSString stringWithFormat:@"%@ - \n\t firstName: %@; \n\t lastName: %@; \n\t uniqueId: %@; \n", [super description], _firstName, _lastName, _uniqueId]; } - (NSUInteger)hash { NSUInteger subhashes[] = {[_firstName hash], [_lastName hash], [_uniqueId hash]}; NSUInteger result = subhashes[0]; for (int ii = 1; ii < 3; ++ii) { unsigned long long base = (((unsigned long long)result) << 32 | subhashes[ii]); base = (~base) + (base << 18); base ^= (base >> 31); base *= 21; base ^= (base >> 11); base += (base << 6); base ^= (base >> 22); result = base; } return result; } @end ``` -------------------------------- ### Post Model Source: https://github.com/instagram/iglistkit/blob/main/Guides/Modeling and Binding.md Defines the data structure for a post, including username, timestamp, image URL, likes, and comments. ```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 } } ``` -------------------------------- ### IGListTransitionData initFromObjects:toObjects:toSectionControllers: Objective-C Source: https://github.com/instagram/iglistkit/blob/main/docs/Classes/IGListTransitionData.html Objective-C initializer for IGListTransitionData. ```objc - (instancetype)initFromObjects:(NSArray *)fromObjects toObjects:(NSArray *)toObjects toSectionControllers:(NSArray *)toSectionControllers NS_DESIGNATED_INITIALIZER; ``` -------------------------------- ### Swift Declaration for 'from' Source: https://github.com/instagram/iglistkit/blob/main/docs/Classes/IGListMoveIndexPath.html Swift declaration for the 'from' property. ```swift var from: IndexPath { get } ``` -------------------------------- ### objects Method Source: https://github.com/instagram/iglistkit/blob/main/docs/Classes/IGListAdapter.html Returns a copy of all the objects currently driving the adapter. ```Objective-C - (nonnull NSArray *)objects; ``` ```Swift func objects() -> [Any] ``` -------------------------------- ### Objective-C Method Signature Source: https://github.com/instagram/iglistkit/blob/main/docs/Protocols/IGListCollectionViewDelegateLayout.html The Objective-C method signature for customizing layout attributes. ```Objective-C (UICollectionViewLayoutAttributes *)attributes atIndexPath:(NSIndexPath *)indexPath; ``` -------------------------------- ### Helper method to translate Core Data objects into ViewModel objects Source: https://github.com/instagram/iglistkit/blob/main/Guides/Working with Core Data.md 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) } } ``` -------------------------------- ### Objective-C Interface Source: https://github.com/instagram/iglistkit/blob/main/docs/Classes/IGListBindingSingleSectionController.html Objective-C interface for IGListBindingSingleSectionController. ```objc @interface IGListBindingSingleSectionController<\ __covariant ViewModel : id , Cell : UICollectionViewCell *> \ : IGListSectionController ``` -------------------------------- ### ActionCell awakeFromNib Source: https://github.com/instagram/iglistkit/blob/main/Guides/Modeling and Binding.md Adds a target and action to the likeButton in ActionCell. ```swift override func awakeFromNib() { super.awakeFromNib() likeButton.addTarget(self, action: #selector(ActionCell.onHeart), for: .touchUpInside) } ``` -------------------------------- ### viewForSupplementaryElementOfKind:atIndex: Method Source: https://github.com/instagram/iglistkit/blob/main/docs/Protocols/IGListSupplementaryViewSource.html Asks the SupplementaryViewSource for a configured supplementary view for the specified kind and index. It's important to dequeue a view from the IGListCollectionContext instead of allocating a new one. ```objc - (nonnull __kindof UICollectionReusableView *)viewForSupplementaryElementOfKind:(nonnull NSString *)elementKind atIndex:(NSInteger)index; ``` ```swift func viewForSupplementaryElement(ofKind elementKind: String, at index: Int) -> UICollectionReusableView ``` -------------------------------- ### objectsForListAdapter: Source: https://github.com/instagram/iglistkit/blob/main/docs/Protocols/IGListAdapterDataSource.html Asks the data source for the objects to display in the list. ```objc - (nonnull NSArray> *)objectsForListAdapter: (nonnull IGListAdapter *)listAdapter; ``` ```swift func objects(for listAdapter: IGListAdapter) -> [any ListDiffable] ``` -------------------------------- ### PostSectionController conforming to ActionCellDelegate Source: https://github.com/instagram/iglistkit/blob/main/docs/modeling-and-binding.html Swift code showing PostSectionController conforming to ActionCellDelegate and implementing didTapHeart. ```swift final class PostSectionController: ListBindingSectionController, ListBindingSectionControllerDataSource, ActionCellDelegate { // ... // MARK: ActionCellDelegate func didTapHeart(cell: ActionCell) { print("like") } ``` -------------------------------- ### showHeaderWhenEmpty Source: https://github.com/instagram/iglistkit/blob/main/docs/Classes/IGListCollectionViewLayout.html Set this to `YES` to show sticky header when a section had no item. Default is `NO`. ```Objective-C @property (nonatomic) BOOL showHeaderWhenEmpty; ``` ```Swift var showHeaderWhenEmpty: Bool { get set } ``` -------------------------------- ### Post-to-view-models transformation Source: https://github.com/instagram/iglistkit/blob/main/Guides/Modeling and Binding.md Implementation of the sectionController(_:viewModelsFor:) method to transform a Post model into an array of ListDiffable view models. ```swift // MARK: ListBindingSectionControllerDataSource func sectionController( _ sectionController: ListBindingSectionController, 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 } ``` -------------------------------- ### ActionCell onHeart Implementation Source: https://github.com/instagram/iglistkit/blob/main/Guides/Modeling and Binding.md Implements the onHeart method to forward the button tap to the delegate. ```swift func onHeart() { delegate?.didTapHeart(cell: self) } ```