CollectionView reloadItems (at:) вызывает didSet () в нескольких ячейках - PullRequest
0 голосов
/ 24 мая 2018

Я работаю над приложением, которое имеет UICollectionView с бесконечной прокруткой.Каждая ячейка имеет кнопку «Нравится».Проблема в том, что чем меньше я прокручиваю, тем медленнее кнопка «Мне нравится» меняет свой цвет при нажатии.

Это может занять до 3 секунд между print("BEGIN") и print("END") в моем коде.Я также заметил, что print(post) вызывается десятки раз, и он печатает десятки сообщений, на которых я не нажал кнопку «Мне нравится».Я хочу, чтобы он вызывал только didSet в ячейке, которую я обновляю.

Может кто-нибудь объяснить, почему кажется, что он вызывает didSet в нескольких ячейках, а не только в одной ячейке, которую я нажал?Это как-то связано с тем, что клетки используются повторно?

Как бы вы решили эту проблему с длительной задержкой?Я бы хотел, чтобы ячейка обновляла изображение как выбранное изображение без такой большой задержки.

protocol HomePostCellDelegate {
    func didTapLike(for cell: HomePostCell)
}

class HomePostCell: UICollectionViewCell {

    var delegate: HomePostCellDelegate?

    var post: Post? {
        didSet {
            print(post)
            likeButton.setImage(post?.isLiked == true ? #imageLiteral(resourceName: "like_selected").withRenderingMode(.alwaysTemplate) : #imageLiteral(resourceName: "like_unselected").withRenderingMode(.alwaysTemplate), for: .normal)
            likeButton.tintColor = .white

           // ...
        }
    }

    lazy var likeButton: UIButton = {
        let button = UIButton(type: .system)
        button.setImage(#imageLiteral(resourceName: "like_unselected").withRenderingMode(.alwaysOriginal), for: .normal)
        button.addTarget(self, action: #selector(handleLike), for: .touchUpInside)
        return button
    }()

    @objc func handleLike() {
        NSLog("@objc func handleLike()")
        delegate?.didTapLike(for: self)
    }
    // ...
}

class HomeController: UICollectionViewController, UICollectionViewDelegateFlowLayout, HomePostCellDelegate {

    // ...

    func didTapLike(for cell: HomePostCell) {

        let generator = UIImpactFeedbackGenerator(style: .light)
        generator.impactOccurred()

        guard let indexPath = collectionView?.indexPath(for: cell) else { return }
        guard let post = cell.post else { return }

        cell.post.isLiked = !cell.post.isLiked

        if cell.post.isLiked {
            cell.post.numberOfLikes += 1
        } else {
            cell.post.numberOfLikes -= 1
        }

        print("BEGIN")
        self.collectionView?.reloadItems(at: [indexPath])
        print("END")
    }
}

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    if indexPath.item == self.presenter.posts.count - 5 && !presenter.isFinishedPaging && !presenter.isCurrentlyPaging  {

        presenter.isCurrentlyPaging = true

        presenter.paginatePosts(withSuccess: { [weak self] () in
            self?.collectionView?.refreshControl?.endRefreshing()
            self?.collectionView?.reloadData()
            self?.presenter.isCurrentlyPaging = false
        }) { [weak self] (errorMessage) in
            self?.presenter.isCurrentlyPaging = false
            print(errorMessage)
        }
    }

    if presenter.posts.count == 0 {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: errorCellId, for: indexPath) as! ErrorCell

        setUpErrorCellAnimation(cell: cell)

        return cell
    } else if presenter.posts[indexPath.item].id == nil {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: adCellId, for: indexPath) as! AdCell

        // some ad logic here
        // ...

        cell.contentView.addSubview(bannerView)

        return cell
    } else {

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! HomePostCell
        cell.delegate = self

        if presenter.isAdmin && presenter.isInAdminView {
            cell.isInAdminView = true
        } else {
            cell.isInAdminView = false
        }

        cell.post = presenter.posts[safe: indexPath.item]

        return cell
    }
}

ОБНОВЛЕНИЕ:

Трассировка стека при помещении точки останова в метод didSet: enter image description here

...