IGListKit: Invalid number of items in section

New issue checklist

General information

  • IGListKit version: 3.0.0
  • iOS version(s): 10.3.2
  • CocoaPods/Carthage version: CocoaPods 1.2.1
  • Xcode version: AppCode 2017.1.2
  • Devices/Simulators affected: Device iPhone 6S
  • Reproducible in the demo project? (Yes/No): Yes
  • Related issues: None

Debug information

Hi guys! Basically I’m stuck with one crash and I’m not getting why.

Model

import Foundation
import IGListKit

class CategoryDetailsSection: NSObject {
    var images: [Image]
    var offSet: OffSet

    init(withImages images: [Image], offSet: OffSet) {
        self.images = images
        self.offSet = offSet
        super.init()
    }
}

// MARK: - ListDiffable
extension CategoryDetailsSection: ListDiffable {

    func diffIdentifier() -> NSObjectProtocol {
        return self
    }

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

In ViewController I have the an endpoint response that I need to display

func displayGetCategoryDetailsSuccess(viewModel: CategoryDetailsModel.GetCategoryDetails.ViewModel) {
    activityView.stopAnimating()
    guard case .success(let categoryDetailsSection) = viewModel.resultData else { return }
    self.categoryDetailsSection.offSet = categoryDetailsSection.offSet
    self.categoryDetailsSection.images.append(contentsOf: categoryDetailsSection.images)
    adapter.performUpdates(animated: true, completion: nil)
}

ListAdapterDataSource is:

extension CategoryDetailsViewController: ListAdapterDataSource {

    func objects(for listAdapter: ListAdapter) -> [ListDiffable] {
        return [categoryDetailsSection]
    }

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

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

categoryDetailsSection is an CategoryDetailsSection object which was init in this way:

fileprivate var categoryDetailsSection = CategoryDetailsSection(withImages: [Image](), 
                                                                offSet: OffSet(inPage: 0, maxPerPage: 0))

SectionController is:

class CategoryDetailsSectionController: ListSectionController {

    // MARK: - Logic Properties
    fileprivate var categoryDetailsSection: CategoryDetailsSection!

    override func numberOfItems() -> Int {
        return categoryDetailsSection.images.count
    }

    override func sizeForItem(at index: Int) -> CGSize {
        return CGSize(width: collectionContext!.containerSize.width - 50.0, height: collectionContext!.containerSize.width - 50.0)
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cell = collectionContext?.dequeueReusableCell(of: CategoryDetailsSectionCell.self, for: self, at: index) as! CategoryDetailsSectionCell
        cell.loadUIObjects(withImage: categoryDetailsSection.images[index])
        return cell
    }

    override func didUpdate(to object: Any) {
        categoryDetailsSection = object as? CategoryDetailsSection
    }

    override func didSelectItem(at index: Int) {

    }
}

So, in ViewController viewDidLoad() is where the endpoint is called and, after I got the response and I parse it, the func displayGetCategoryDetailsSuccess(viewModel: CategoryDetailsModel.GetCategoryDetails.ViewModel) method is called and…CRASH 😃

2017-05-28 13:39:25.332231+0200 UpToU[2029:690351] *** Assertion failure in -[UICollectionView _endItemAnimationsWithInvalidationContext:tentativelyForReordering:animator:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3600.8.1/UICollectionView.m:5781

2017-05-28 13:39:25.332941+0200 UpToU[2029:690351] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of items in section 0.  The number of items contained in an existing section after the update (10) must be equal to the number of items contained in that section before the update (0), plus or minus the number of items inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of items moved into or out of that section (0 moved in, 0 moved out).'
*** First throw call stack:
(0x18be52fe0 0x18a8b4538 0x18be52eb4 0x18c8ea720 0x19288ec38 0x19289270c 0x1928929ec 0x19289284c 0x1928927d0 0x19215a48c 0x100d9e820 0x100da1424 0x18ad0a9e0 0x18ad0a9a0 0x18ad0f5e8 0x18be010c8 0x18bdfece4 0x18bd2eda4 0x18d798074 0x191fe9058 0x100037194 0x18ad3d59c)
libc++abi.dylib: terminating with uncaught exception of type NSException
Signal: SIGABRT (signal SIGABRT)

Any clue why? If I’m implementing it wrong, how can I add images and display them?

FYI The reason I’m doing it is because when user reach the bottom of the ScrollView I need to fetch new elements and show them. So I need to append new elements, in this case images, in the previous SectionController. I’m trying this and seems working but, it is the correct way?

func displayGetCategoryDetailsSuccess(viewModel: CategoryDetailsModel.GetCategoryDetails.ViewModel) {
    activityView.stopAnimating()
    guard case .success(let categoryDetailsSection) = viewModel.resultData else { return }
    guard let sectionController = adapter.sectionController(forSection: 0) as? CategoryDetailsSectionController else { return }
    sectionController.collectionContext?.performBatch(animated: true,
                                                       updates: { batchContext in
                                                           let previousCount = sectionController.categoryDetailsSection.images.count
                                                           let startIndex = previousCount == 0 ? 0 : previousCount
                                                           let endIndex = previousCount + categoryDetailsSection.images.count - 1
                                                           sectionController.categoryDetailsSection.offSet = categoryDetailsSection.offSet
                                                           sectionController.categoryDetailsSection.images.append(contentsOf: categoryDetailsSection.images)
                                                           batchContext.insert(in: sectionController, at: IndexSet(startIndex...endIndex))
                                                       },
                                                       completion: { completed in
                                                           self.categoryDetailsSection = sectionController.categoryDetailsSection
                                                       }
    )
}

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 16 (8 by maintainers)

Commits related to this issue

Most upvoted comments

@rnystrom sounds good. Alright then, keep me posted when a guide will be done. Would be nice to have an example with a UICollectionView like in LoadMoreViewController.swift but instead of add section, add elements to the section controller array model.

Any update on this @cikpis ? An alternative is always to paper sketch a simple version of what you want to archieve… Maybe I can throw something quick together. The example projects are pretty comprehensive now and I can not really get what you want to archieve that can not be replicated by combining snippets and designs from those.

@rnystrom still waiting the guideline for binding controller 😃

Any update on this? Should we close?

@cikpis still hoping to set aside more time for it among a bunch of other priorities atm. I’ve explored a lot of uses for this SC in Instagram and another sample app, so several learnings and best practices. Will get this prioritized higher.

@rnystrom thanks! Even though seems there is no example or guide of how to use it 😃 Also I don’t know if to be afraid of your “just work” xD

Anyway, do you mind to redirect me in the correct guide or example for IGListBindingSectionController? I haven found nothing about that, thanks in advance!