TextureGroup / Texture

Smooth asynchronous user interfaces for iOS apps.
https://texturegroup.org/
Other
7.99k stars 1.29k forks source link

beginBatchFetch keeping firing with IGListKit #1643

Open lohenyumnam opened 4 years ago

lohenyumnam commented 4 years ago

Version: 2.8 Xcode: 10.3

Problem:

I am using ASColllectionNode with IGListKit, on SectionController which I have implemented using ASSectionController and ListSectionController has a beginBatchFetch Method. which keep firing even when I am no way near the end. is this normal or am I doing something wrong.

I also tried setting the node.leadingScreensForBatching = 1 but it has no effect. and I am also using ListCollectionViewLayout as my collectionNode's layout

Here is the sample of my SectionController

protocol ExploreUserSectionControllerDelegate: AnyObject {
    func beginBatchFetch(with context: ASBatchContext)
    func didSelect(atIndex index: Int, withUsername username: String)
}

class ExploreUserSectionController: ListSectionController, ASSectionController {
    weak var userOfExploreGrid: UserOfExploreGrid?
    weak var delegate: ExploreUserSectionControllerDelegate?

    let numberOfColumn: CGFloat = 2

    override init() {
        super.init()
        inset = UIEdgeInsets(top: 0, left: 5, bottom: 5, right: 0)
        self.minimumInteritemSpacing    = 0
        self.minimumLineSpacing         = 0
    }

    deinit {
        #if DEBUG
        print("OpinionCellUserProfileSectionControllerDelegate Killed")
        #endif
    }

    // MARK: ListSectionController
    override func didUpdate(to object: Any) {
        guard let userOfExploreGrid   = object as? UserOfExploreGrid else { return }
        self.userOfExploreGrid        = userOfExploreGrid
    }

    override func numberOfItems() -> Int {
        return 1
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cell = ASIGListSectionControllerMethods.cellForItem(at: index, sectionController: self)
        return cell
    }

    override func sizeForItem(at index: Int) -> CGSize {
        let size  = ASIGListSectionControllerMethods.sizeForItem(at: index)
        return size
    }

    override func didSelectItem(at index: Int) {
        if let userOfExploreGrid_ = userOfExploreGrid {
            delegate?.didSelect(atIndex: index, withUsername: userOfExploreGrid_.username)
        }

    }

    // MARK: - ASSectionController
    func nodeBlockForItem(at index: Int) -> ASCellNodeBlock {
        let nodeBlock: ASCellNodeBlock = { [weak self] in
            let node = ExploreUserCell(withUser: self?.userOfExploreGrid)
            return node
        }
        return nodeBlock
    }

    func nodeForItem(at index: Int) -> ASCellNode {
        let node = ExploreUserCell(withUser: self.userOfExploreGrid)
        return node
    }

    func sizeRangeForItem(at index: Int) -> ASSizeRange {
        let width = collectionContext!.containerSize.width - 15  //- (5 + 5 + 5) - 10 //* 0.97

        let min = CGSize(width: width / numberOfColumn, height: 0)
        let max = CGSize(width: width / numberOfColumn, height: 1000)
        return ASSizeRange(min: min, max: max)
    }

    func beginBatchFetch(with context: ASBatchContext) {
        self.delegate?.beginBatchFetch(with: context)
    }
}
varyP commented 4 years ago

@lohenyumnam the default is 2 screens for batching. Unless you say collectionNode.leadingScreensForBatching = 0, it'll pre-fetch 2 screens before the end.

lohenyumnam commented 4 years ago

@varyP Ya I did try setting collectionNode.leadingScreensForBatching = 0 too but no effect, beginBatchFetch keep firing like crazy.

But I notice something, as I am using it with IGListKit and my layout is two column grid. I am stuck with ListCollectionViewLayout. But if I change the layout to UICollectionViewFlowLayout collectionNode.leadingScreensForBatching = 0 seems to work but not with ListCollectionViewLayout. I think something is missing in ListCollectionViewLayout.

varyP commented 4 years ago

@lohenyumnam , try this override func didLoad() { super.didLoad() collectionNode.leadingScreensForBatching = 0 }

lohenyumnam commented 4 years ago

@varyP when I put collectionNode.leadingScreensForBatching = 0 inside the didLoad() method, the IGlistKit's ASSectionController's func beginBatchFetch(with context: ASBatchContext) or willBeginBatchFetchWithContext of Collection ASCollectionNode never got fired. I even tried setting ASCollection's delegate to self.

For Now my current Solution is:

let currentVisibleCellSection = self.collectionNode.indexPathsForVisibleItems.last?.section ?? 0
            let distance = self.loader.usersOfExploreGrid.count - currentVisibleCellSection
            if distance < 25 {
                self.fetchUsers()
            } else {
                context.completeBatchFetching(true)
            }

I manually check if the current visible cell is really near the end of data. so I took the last visibleCell Indexpath's section and check agaist the count of data from the loader if the count is really low it means the cell is near the end and need to fetch more data.

varyP commented 4 years ago

when I put collectionNode.leadingScreensForBatching = 0 inside the didLoad() method, the IGlistKit's ASSectionController's func beginBatchFetch(with context: ASBatchContext) or willBeginBatchFetchWithContext of Collection ASCollectionNode never got fired. I even tried setting ASCollection's delegate to self.

I thought that's what you wanted, setting it to 0 would mean that you don't want it to be called. How about try 0.25, since it's a CGFloat. But remember to call it in didLoad.

lohenyumnam commented 4 years ago

@varyP Thanks for the advice, but its seems the problem is with ListCollectionViewLayout when ever I set leadingScreensForBatching any value greater then 0 batchFetch firing won't stop. but I noticed that when CollectionNode is scrolling it stop firing.