我有
UICollectionViewCompositionalLayout
。在 didSelectItemAt
我开始下载文件。在集合视图项目中,我有一个标签,显示下载文件的百分比。我使用此代码来执行此操作并更新我的单元格:
func createDataSource() {
dataSource = UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView) { collectionView, indexPath, item in
switch self.sections[indexPath.section].identifier {
case "cell":
let cell = self.configure(DCell.self, with: item, for: indexPath)
if indexPath.row < self.items.count {
let item = self.items[indexPath.row]
switch item.state {
case .downloading: cell.title.text = "\(String(format: "%.f%%", item.progress * 100))"
case .completed: cell.title.text = "Completed"
case .failed: cell.title.text = "Fail"
case .none: break
}
}
return cell
default: return self.configure(DCell.self, with: item, for: indexPath)
}
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// activate the download manager code...
let url = URL(string: "http")!
let downloadManager = DownloadManager()
downloadManager.identifier = indexPath.row+1
downloadManager.collectionId = 0
downloadManager.folderPath = "\(indexPath.row+1)"
let downloadTaskLocal = downloadManager.activate().downloadTask(with: url)
downloadTaskLocal.resume()
// get progress:
downloadManager.onProgress = { [weak self] (row, collection, progress) in
guard let self = self else { return }
DispatchQueue.main.async {
self.items[row - 1].progress = progress
switch progress {
case 1.0: self.items[row - 1].state = .completed
case _: self.items[row - 1].state = .downloading
}
self.reloadItem(indexPath: .init(row: row - 1, section: 0))
}
}
}
func reloadItem(indexPath: IndexPath) {
guard let needReloadItem = dataSource!.itemIdentifier(for: indexPath) else { return }
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
snapshot.appendSections(sections)
for section in sections { snapshot.appendItems(section.item, toSection: section) }
dataSource?.apply(snapshot)
snapshot.reloadItems([needReloadItem])
dataSource?.apply(snapshot, animatingDifferences: false)
}
来自 downloadManager 的代码以获取进度:
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
if totalBytesExpectedToWrite > 0 {
if let onProgress = onProgress { calculateProgress(session: session, completionHandler: onProgress) }
}
}
private func calculateProgress(session : URLSession, completionHandler : @escaping (Int, Int, Float) -> ()) {
session.getTasksWithCompletionHandler { (tasks, uploads, downloads) in
let progress = downloads.map({ (task) -> Float in
if task.countOfBytesExpectedToReceive > 0 { return Float(task.countOfBytesReceived) / Float(task.countOfBytesExpectedToReceive)
} else { return 0.0 }
})
completionHandler(session.getSessionDescription(), Int(session.accessibilityHint!)!, progress.reduce(0.0, +))
}
}
但是当我的文件正在下载并且我使用此方法
reloadItem(indexPath: IndexPath)
来更新单元格时,我在滚动集合视图时会遇到一些冻结,并且如果我再次单击当前显示下载进度的单元格,则会冻结。我的问题出在这个方法中reloadItem(indexPath: IndexPath)
。但是如何通过单元格更新来解决这个问题呢?
请尝试以下更改:
func reloadItem(indexPath: IndexPath) {
guard let needReloadItem = dataSource!.itemIdentifier(for: indexPath) else { return }
guard var snapshot = dataSource?.snapshot() else { return }
snapshot.reloadItems([needReloadItem])
dataSource?.apply(snapshot, animatingDifferences: false)
}
一旦形成初始快照,后续更改通常应引用相同的快照。这确保了数据源可以在当前保存的快照和新应用的快照之间执行有效的差异。