The collection view will show list of 20 movies and if user scrolls to the last item, then it'll load another 20. At first I used reloadData() after appending another 20 items to the arrays of movies, And it works. But I believe the correct way to do it is to insertItems() to the collectionView instead of calling reloadData() every single time. After I implemented the insertItems(), Then the error occurs.
Here's the code related to the CollectionView :
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return moviesArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MovieCell", for: indexPath) as! MovieCell
let imageUrl = moviesArray[indexPath.row].posterPath!
let url = URL(string: "https://image.tmdb.org/t/p/w500\(imageUrl)")!
cell.moviePoster.load(url: url)
cell.layer.cornerRadius = 10
return cell
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if indexPath.row == moviesArray.count - 1 {
currentPage += 1
dataManager.downloadAllMoviesJSON(page: currentPage)
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
dataManager.downloadMovieDetailJSON(id: moviesArray[indexPath.row].id) { (data) in
DispatchQueue.main.async {
self.performSegue(withIdentifier: "ToMovieDetail", sender: self)
}
}
And here's the code that handling the movies list loading and appending :
func didGetMovies(dataManager: DataManager, movie: MovieData) {
if currentPage > 1 {
let lastInArray = moviesArray.count
self.moviesArray.append(contentsOf: movie.results)
let newLastInArray = moviesArray.count
let indexPaths = Array(lastInArray...newLastInArray).map{IndexPath(item: $0, section: 0)}
DispatchQueue.main.async {
self.moviesCV.performBatchUpdates({
self.moviesCV.insertItems(at: indexPaths)
}, completion: nil)
}
} else {
moviesArray = movie.results
DispatchQueue.main.async {
self.moviesCV.reloadData()
}
}
}
At first I didn't know that the insertItems() must be inside the performBatchUpdates() but even if I do so, The error still persists. It might be because I've implemented it improperly.
The error is always :
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to insert item 40 into section 0, but there are only 40 items in section 0 after the update'
Perhaps anyone could kindly show the part that seems to be the issue?
The last index of an array is .count - 1
. You have to use the ..<
operator
let indexPaths = Array(lastInArray..<newLastInArray).map{IndexPath(item: $0, section: 0)}
and the performBatchUpdates
block is not needed, it's only useful for simultaneous insert/delete/move operations
DispatchQueue.main.async {
self.moviesCV.insertItems(at: indexPaths)
}