NEW: Start my new Ultimate Portfolio App course with a free Hacking with Swift+ trial! >>

CollectionView Diffable Data Source scrolling unexpectedly

Forums > Swift

My app displays comments, and users can like these comments. The app uses a diffable data source, and when I click on the last row to like the comment, the collection view scrolls to the centre.

Here is a video of the issue https://streamable.com/9vijyx (sorry about he music, my baby daughter was dancing)

Here is some of my code that I think is relevant - you'll see by the comments that I have tried to fix this issue by storing the content offset but it feels VERY hacky. Any help would be greatly appreciated.

    fileprivate func configureDataSource() {
        self.datasource = UICollectionViewDiffableDataSource<Section, PostDetail>(collectionView: self.collectionView) {
            (collectionView: UICollectionView, indexPath: IndexPath, userComment: PostDetail) -> UICollectionViewCell? in
            guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PostDetailCell.reuseIdentifier, for: indexPath) as? PostDetailCell else { fatalError("Cannot create cell")}

            cell.user = self.user
            cell.postDetail = userComment
            cell.likeCommentDelegate = self
            return cell
        }

        var snapshot = NSDiffableDataSourceSnapshot<Section, PostDetail>()
        snapshot.appendSections([.main])
        snapshot.appendItems(self.userComments)
        self.datasource.apply(snapshot, animatingDifferences: true)
    }

    fileprivate func applySnapshot() {
        //Any updates to the snapshot, including likes, will
        //scroll the collectionView, but we want to stay on the cell
        // the user has liked, not scroll, so we store the offset.
        //This is then restored after all updates are complete.

        //let contentOffset = self.collectionView.contentOffset
        var snapshot = NSDiffableDataSourceSnapshot<Section, PostDetail>()
        snapshot.appendSections([.main])
        snapshot.appendItems(self.userComments)
        self.datasource.apply(snapshot, animatingDifferences: true)
        //self.collectionView.contentOffset = contentOffset
    }

    func handleCommentLike(cell: PostDetailCell) {
        print("handle like comment")
        guard let indexPath = self.collectionView.indexPath(for: cell) else { return }

        if self.userComments[indexPath.row].like == nil {
            let userId = user.id
            let postId = feedItem.post.id
            let commentId = self.userComments[indexPath.row].comment.id
            let timestamp = Int(Date().timeIntervalSince1970)

            let commentLike = CommentLike(postId: postId, userId: userId, commentId: commentId, createdTimestamp: timestamp)

            self.viewModel.createLike(commentLike: commentLike) { result in
                switch result {
                case .success(let commentLike):
                    print("\(commentLike)")
                    //
                    self.userComments[indexPath.row].like = commentLike
                    self.applySnapshot()
                case .failure(let error):
                    print("Error creating like: \(error)")
                }
            }
        } else {

            guard let like = self.userComments[indexPath.row].like else { return }
            self.viewModel.un(commentLike: like) { result in
                switch result {
                case .success(let like):
                    print(like)
                    self.userComments[indexPath.row].like = nil
                    self.applySnapshot()
                case .failure(let error):
                    print(error)
                }
            }
        }
    }

   

Hey there, I got your source code from upwork and the problem is with your PostDetail model.

You should change

struct PostDetail {
    let identifier = UUID()
    var comment: Comment
    var like: CommentLike?
    var user: User
}

TO

class PostDetail {
    let identifier = UUID()
    var comment: Comment
    var like: CommentLike?
    var user: User

    init(comment: Comment, like: CommentLike? = nil, user: User) {
        self.comment = comment
        self.like = like
        self.user = user
    }
}

And change the rest of you code accordingly. You should also remove updateSnapshot and just use applySnapshot

Cheers.

   

Another possibility would be to just update the cell directly and don't rely on snapshot for this simple change. Without snapshot, you could get reference to the cell from the collection view and set it to like state.

   

Hacking with Swift is sponsored by Fernando Olivares

SPONSORED Would you describe yourself as knowledgeable, but struggling when you have to come up with your own code? Fernando Olivares has a new book containing iOS rules you can immediately apply to your coding habits to see dramatic improvements, while also teaching applied programming fundamentals seen in refactored code from published apps.

Try the book!

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.