我有两个水平的collectionViews-一个显示多个帖子,另一个显示与发布日期相对应的时间轴。每天在时间轴collectionView中都有一个垂直单元格。如果该天有帖子,则会以彩色显示。
例如,在此图像中,有两个帖子在不同的日期。活动帖子比其他帖子更厚。
为了使事情变得更复杂,将使用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调用在这里不起作用?