Lazy fetching of objects in collection view

Hi everyone,


I have a collection view which displays the content of an array that fetches the data from a database (asychronously). First, I only want to fetch 10 records, once the user scrolls down to the end of the collection view, another 10 records should be fetched.

I have following code so far:


// load challenges from database
    func loadChallenges() {
        
       self.view.addSubview(activityView)
       self.view.bringSubview(toFront: activityView)
        
        algoliaSearch.fetchChallengeInformationBySearchValue(completionHandler: { (challengeArray) in
            
            if(challengeArray.count == 0) {
                self.activityView.removeFromSuperview()
                return
            }
            // if challenge contains already data, clear the existing data and get the new content
            // search is done through the api of algolia. We search by using indexes. Each index contains 10 records
            // First, we load 10 objects using index = 0 which is set to 'PAGINATION'
            self.challengeArray.removeAll()
            self.challengeArray = challengeArray
            
            self.removeBlockedChallengesFromArray(_challengeArray: self.challengeArray)
            
        }, searchValue: EMPTY_MESSAGE, page: PAGINATION) 
    }
...

 // method that should load the next 10 objects when collection view is scrolled down to the end
 func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
        
         // if we reached the 10 objects already, we can increase the PAGINATION variable and fetch the next 10 records
        if (challengeArray.count > (10 * i)) {
            PAGINATION = PAGINATION + 1
            i = i + 1
        }
        
        // if last row of the table view is reached, load the next items
        if indexPath.row  == challengeArray.count - 1 {
          
            algoliaSearch.fetchChallengeInformationBySearchValue(completionHandler: { (challengeArray) in
                            
                // if there is no data, we can return from the function
                if (challengeArray.count == 0) {
                    return
                }
                
                for challengeObject in challengeArray {
                    // check if data is already stored within the array, avoid duplicates
                    /* The problem is, using algolia api, it is not possible to fetch data between indexes, so therefore
                      we also fetch the first 10 records again. Any idea how to solve that as well? */
                    let results = self.challengeArray.filter { $0.id == challengeObject.id}
                    if (results.count == 0) {
                        self.challengeArray.append(challengeObject)
                    }
                }
                self.mainCollectionView?.reloadData()
                
            }, searchValue: "", page: PAGINATION) 
        }
    }


I tried to explain my problem using comments in the code snippt above. Using the code snippets above, my problem is that data is fetched even if I haven't scrolled down in my collection view.


I was wondering if anyone could help me? Thanks.

Replies

Why do you want this ? To avoid user having to wait too long ?


Did you consider moving the fetch in another thread than the main thread ?

Doing so, fetching would take place without blocking UI on the main thread.

Hi Claude,


the UI is not blocking at all in the moment. The loadChallenges() function is only called once in the viewDidLoad() method.

My problem is how I load the next 10 objects if I scroll to the end of collection view only. With that code as you can see above, it somehows makes an endless loop and fetches the data all the time.

Sorry if I missed it - pls. show any code you have for prefetch and/or asyncfetch


Ref.: https://developer.apple.com/documentation/uikit/uicollectionviewdatasourceprefetching/prefetching_collection_view_data