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

Crash on Load More, after network call, updating existing array #1303

Open kwstasna opened 5 years ago

kwstasna commented 5 years ago

New issue checklist

General information

Hello. I have this issue with IGList kit. So in my project i have a "Loading more" functionality about images downloaded from my API, paginated.

So there is a class which holds the

class ProfileImages: ListDiffable {

    var nextMaxID: String?
    var images: [Images]?

    init(nextMaxID: String? = nil, images: [Images]? = []) {
        self.images = images
        self.nextMaxID = nextMaxID
    }

    func diffIdentifier() -> NSObjectProtocol {
        return (nextMaxID ?? "ProfileImages") as NSObjectProtocol
    }

    func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
        guard self !== object else { return true }
        guard let object = object as? ProfileImages else { return false }
        return nextMaxID == object.nextMaxID
    }
}

In my viewModel i have this function which gives me the above class but with the newest images array without the previous ones, since its paginated.

    func updateUserImages(with userID: Int?, and nextMaxID: String, onSuccess: @escaping (ProfileImages) -> Void) {
        userService.getUserImages(with: userID, nextMaxId: nextMaxID) { (feedResponse) in
            let newProfileImages = ProfileImages(nextMaxID: feedResponse.nextMaxId, images: feedResponse.items)
            onSuccess(newProfileImages)
        }
    }

And in my View Controller, in the scroll delegate of adapter, I have your paradigm from LoadMoreSectionController

extension ProfileViewController: UIScrollViewDelegate {
    func scrollViewWillEndDragging(_ scrollView: UIScrollView,
                                   withVelocity velocity: CGPoint,
                                   targetContentOffset: UnsafeMutablePointer<CGPoint>) {

        guard let object = self.profileViewModel.viewData.value[1] as? ProfileImages,
            let nextMaxID = object.nextMaxID,
            var oldImages = object.images else { return }

        let distance = scrollView.contentSize.height - (targetContentOffset.pointee.y + scrollView.bounds.height)
        if !loading && distance < 200 {
            loading = true
            adapter.performUpdates(animated: true, completion: nil)

            DispatchQueue.global(qos: .default).async {
                DispatchQueue.main.async {
                    self.profileViewModel.updateUserImages(with: self.userService.user.pk, and: nextMaxID, onSuccess: { profileImages in
                        self.loading = false
                        oldImages.append(contentsOf: profileImages.images ?? []) // here i update the previews array by appending the new arrays
                        object.images = oldImages // and here i replace the previews array with the new one which has all the images.
                        object.nextMaxID = profileImages.nextMaxID
                        self.adapter.performUpdates(animated: true, completion: nil)  // Although if i use `self.adapter.reloadData()` its not crashing although i read on the docs that it's not a proper way to reload stuff.
                    })
                }
            }

        }
    }
}

And when i scroll down it crashes.

2019-02-03 15:31:00.520794+0200 ProjectName [20694:7628667] *** Assertion failure in -[IGListAdapter _visibleSectionControllersFromLayoutAttributes](), /Users/trypow-mac/Desktop/ProjectName/Pods/IGListKit/Source/IGListAdapter.m:515
2019-02-03 15:31:00.527576+0200 ProjectName[20694:7628667] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Section controller nil for cell in section 1'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010a3161bb __exceptionPreprocess + 331
    1   libobjc.A.dylib                     0x00000001098b4735 objc_exception_throw + 48
    2   CoreFoundation                      0x000000010a315f42 +[NSException raise:format:arguments:] + 98
    3   Foundation                          0x0000000104fdf940 -[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:] + 166
    4   IGListKit                           0x000000010568eb99 -[IGListAdapter _visibleSectionControllersFromLayoutAttributes] + 1273
    5   IGListKit                           0x000000010568e67c -[IGListAdapter visibleSectionControllers] + 540
    6   IGListKit                           0x00000001056935a4 -[IGListAdapter scrollViewDidScroll:] + 196
    7   UIKitCore                           0x000000011333ba5b -[UIScrollView(UIScrollViewInternal) _notifyDidScroll] + 66
    8   UIKitCore                           0x00000001133220ef -[UIScrollView setContentOffset:] + 1007
    9   UIKitCore                           0x00000001133337e5 -[UIScrollView _smoothScrollWithUpdateTime:] + 2967
    10  UIKitCore                           0x0000000113333bb6 -[UIScrollView _smoothScrollDisplayLink:] + 379
    11  QuartzCore                          0x00000001063300a2 _ZN2CA7Display11DisplayLink14dispatch_itemsEyyy + 818
    12  QuartzCore                          0x00000001063fcbb9 _ZL22display_timer_callbackP12__CFMachPortPvlS1_ + 297
    13  CoreFoundation                      0x000000010a24f5a6 __CFMachPortPerform + 150
    14  CoreFoundation                      0x000000010a27bf69 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 41
    15  CoreFoundation                      0x000000010a27b5bb __CFRunLoopDoSource1 + 459
    16  CoreFoundation                      0x000000010a275b2e __CFRunLoopRun + 2526
    17  CoreFoundation                      0x000000010a274e11 CFRunLoopRunSpecific + 625
    18  GraphicsServices                    0x000000010cef51dd GSEventRunModal + 62
    19  UIKitCore                           0x0000000112ec181d UIApplicationMain + 140
    20  ProjectName                   0x0000000102022424 main + 68
    21  libdyld.dylib                       0x000000010b3ee575 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

Am I missing something ?

kwstasna commented 5 years ago

@rnystrom any idea or suggestion ?