Instagram / IGListKit

A data-driven UICollectionView framework for building fast and flexible lists.
https://instagram.github.io/IGListKit/
MIT License
12.84k stars 1.54k forks source link

Reloading ListSectionController inside ListStackedSectionController reloads entire StackedSectionController #1008

Open Marcocanc opened 6 years ago

Marcocanc commented 6 years ago

When reloading a ListSectionController inside a ListStackedSectionController, the entire ListStackedSectionController is reloaded.

Note: self refers to a ListSectionController which is inside a ListStackedSectionController

self.collectionContext?.performBatch(animated: true, updates: { (batchContext) in
    batchContext.reload(self)
})

General information

rnystrom commented 6 years ago

@Marcocanc ya this is intended behavior atm. Can you tell me what behavior you would expect?

Marcocanc commented 6 years ago

@rnystrom Here's an example ListStackedSectionController:

┌────────────────────────────┐                              
│  HeaderSectionController   │ ListSingleSectionController  
├────────────────────────────┤                              
│                            │                              
│                            │                              
│                            │                              
│                            │    ListSectionController     
│  ContentSectionController  │  (variable number of cells)  
│                            │                              
│                            │                              
│                            │                              
│                            │                              
├────────────────────────────┤                              
│  FooterSectionController   │ ListSingleSectionController  
└────────────────────────────┘                                                          

calling batchContext.reload(self) from the ContentSectionController I would expect only that controller to reload. Instead the other two are reloaded as well

Is there another way to only reload all cells inside a nested ListSectionController?

XiaoYulong commented 5 years ago

@Marcocanc , I just came across the same situation as you did. Below is my way of work around:

extension ListSectionController {
    fileprivate var stackedSectionController: ListStackedSectionController? {
        if collectionContext is ListStackedSectionController {
            // swiftlint:disable:next force_cast
            return (self.collectionContext as! ListStackedSectionController)
        } else {
            return nil
        }
    }
}

extension ListStackedSectionController {
    fileprivate var sectionControllers: NSOrderedSet? {
        if responds(to: Selector(("sectionControllers"))) {
            let unmanaged = perform(Selector(("sectionControllers")))
            if unmanaged?.takeUnretainedValue() is NSOrderedSet? {
                // swiftlint:disable:next force_cast
                return unmanaged?.takeUnretainedValue() as! NSOrderedSet?
            }
        }
        return nil
    }
}

and use like this:

if let sectionControllers = strongSelf.stackedSectionController?.sectionControllers,
        // swiftlint:disable:next force_cast
        strongSelf === (sectionControllers.firstObject as! ListSectionController) {
        strongSelf.collectionContext?.performBatch(animated: false, updates: { (batchContext) in
            batchContext.reload(in: strongSelf, at: [0])
        })
    } else {
        strongSelf.collectionContext?.performBatch(animated: false, updates: { (batchContext) in
            batchContext.reload(strongSelf)
        })
    }

here I reload the first item of stackedSectionController, cause in my case I need to reload the first sub section controller, and that sub section controller only has one item. In your case, if's need a little extra work to calculate the real indexes you want to reload.