Ошибка подтверждения с CollectionView.reloadItems (по адресу: CollectionView.indexPathsForVisibleItems) - PullRequest
0 голосов
/ 10 декабря 2018

У меня есть два горизонтальных представления коллекции - один показывает количество сообщений, а другой - временную шкалу, соответствующую датам публикации.Каждый день имеет вертикальную ячейку на временной шкале collectionView.Это окрашено, если есть пост в тот день.

enter image description here

Например, на этом изображении два сообщения в разные дни.Активный пост толще остальных.

Чтобы сделать это более сложным, посты загружаются с помощью NSFetchedResultsController, так что когда пост добавляется или удаляется, postsCollectionView И временная шкала обновляется.Вот метод NSFetchedResults, который вызывается, когда это происходит:

extension TimelineViewController: NSFetchedResultsControllerDelegate {
    //autoUpdate Stuff
    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>,
                    didChange anObject: Any,
                    at indexPath: IndexPath?,
                    for type: NSFetchedResultsChangeType,
                    newIndexPath: IndexPath?){
        switch type {
        case .insert:
            print("Insert Object: \(String(describing: newIndexPath))")
            blockOperations.append(
                BlockOperation(block: { [weak self] in
                    if let this = self {
                        this.postsCollectionView!.insertItems(at: [newIndexPath!])
                    }
                })
            )
        case .update:
            blockOperations.append(
                BlockOperation(block: { [weak self] in
                    if let this = self {
                        this.postsCollectionView!.reloadItems(at: [indexPath!])
                    }
                })
            )
        case .move:
            blockOperations.append(
                BlockOperation(block: { [weak self] in
                    if let this = self {
                        this.postsCollectionView!.moveItem(at: indexPath!, to: newIndexPath!)
                    }
                })
            )
        case .delete:
            blockOperations.append(
                BlockOperation(block: { [weak self] in
                    if let this = self {
                        this.postsCollectionView!.deleteItems(at: [indexPath!])
                    }
                })
            )
        default: break
        }
    }

    func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
        postsCollectionView!.performBatchUpdates({ () -> Void in
            for operation: BlockOperation in self.blockOperations {
                operation.start()
            }
        }, completion: { (finished) -> Void in
            self.loadTimeline()
            self.blockOperations.removeAll(keepingCapacity: false)
        })
    }
}

, а вот функция loadTimeline, которую он вызывает, когда это делается с анимациями

func loadTimeline(){
        postTimes = posts.fetchedObjects?.map{ $0.timeStamp } as! [Date]
        if postTimes.count > 0 {
            detailsView.isHidden = false
            timelineCollectionView.isHidden = false
            firstPostDate = postTimes.first
            lastPostDate = postTimes.last
            for (i,postTime) in postTimes.enumerated() {
                let day = postTime.days(from: Calendar.current.startOfDay(for: firstPostDate!))
                indexMap[day] = IndexPath(row: i, section: 0)
            }
            let timelineStartDay = Calendar.current.date(byAdding: .day, value: 0, to: firstPostDate!)
            timelineStart = Calendar.current.startOfDay(for: timelineStartDay!)
            timelineEnd = Calendar.current.date(byAdding: .day, value: 0, to: lastPostDate!)

            timelineCollectionView.reloadItems(at: timelineCollectionView.indexPathsForVisibleItems)

            let postTimeStamp = currentPost.timeStamp as Date?
            let timelineIndex = postTimeStamp?.days(from: timelineStart!)
            print(timelineIndex,"timelineIndex")
            let cellIndexPath = IndexPath(item: timelineIndex!,section: 0)
            self.selectedIndexPath = cellIndexPath
            timelineCollectionView.scrollToItem(at: cellIndexPath, at: .centeredHorizontally, animated: true)
        } else {
            timelineCollectionView.isHidden = true
            detailsView.isHidden = true
        }
    }

Когда я это делаю,Я получаю сообщение об ошибке:

2018-12-10 10:30:10.696195-0800 SweatNetOffline[3922:22319314] *** Assertion failure in -[UICollectionView _endItemAnimationsWithInvalidationContext:tentativelyForReordering:animator:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKitCore_Sim/UIKit-3698.84.15/UICollectionView.m:5956
2018-12-10 10:30:10.705622-0800 SweatNetOffline[3922:22319314] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to insert item 1 into section 0, but there are only 1 items in section 0 after the update'

Обратите внимание, что эта ошибка вызвана timelineCollectionView.reloadItems(at: timelineCollectionView.indexPathsForVisibleItems).

Если я закомментирую это, не произойдет сбой, но, конечно, временная шкала не будет перезагружена,

Также данные для временной шкалы установлены следующим образом:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    if collectionView == timelineCollectionView {
        let cell = timelineCollectionView.dequeueReusableCell(withReuseIdentifier: "dayCell", for: indexPath) as! TimelineCollectionViewCell
        let cellDate = Calendar.current.date(byAdding: .day, value: indexPath.item, to: self.timelineStart!)!
        if postTimes.contains(where: { Calendar.current.isDate(cellDate, inSameDayAs: $0) }) {
            cell.backgroundColor = UIColor(red:0.22, green:0.45, blue:0.62, alpha:1.0)
        }
        return cell
    } else {
        ...  // for the post cell
    }
}

, поскольку postTimes обновляется в loadTimeline (). Я не считаю, что вызов reloadData необходим, я просто хочуперезагрузите элементы, которые видны с обновленными postTimes.Почему здесь не работает вызов reloadItems?

...