为何相同搜索词需发起两次网络请求后UICollectionView才会刷新数据
问题根因与解决方案
核心根因
- 自定义布局的
heightForCell代理方法逻辑缺陷:你通过SDWebImageManager.loadImage同步返回图片对象,但该方法是异步下载逻辑,首次搜索时GIF预览图未缓存,方法直接返回nil,导致所有cell高度计算为0,最终集合视图collectionViewContentSize.height为0,没有可见绘制区域,不会触发cellForItemAt数据源方法。第二次输入相同搜索词时,图片已经存入SDWebImage缓存,同步返回图片对象即可计算出正确高度,集合视图内容高度正常,触发cell加载。 - 外部高度约束更新未触发布局:首次搜索后
heightChanged返回高度为0,你将父容器的collectionViewHeightConstraint设为0后未立即触发父视图布局,GIF集合视图本身被压缩为0高度,即使后续有数据也无法展示。
修复方案
1. 优先使用接口返回的GIF元数据计算高度(最优方案)
绝大多数GIF搜索服务(如Giphy、Tenor)都会在返回结果中附带每个GIF资源的宽高字段,你可以将宽高信息存在POGIFModel的item属性中,计算cell高度时直接使用元数据计算,无需等待图片下载,彻底解决该问题:
func heightForCell(givenWidth cellWidth: CGFloat, at indexPath: IndexPath!) -> CGFloat { guard let item = self.viewModel?.gifModel.items[indexPath.row] else { return cellWidth } // 直接用接口返回的宽高计算 let scaleFactor = item.gifHeight / item.gifWidth let imageViewToHighlightedViewSpacing: CGFloat = 4 return cellWidth * scaleFactor + imageViewToHighlightedViewSpacing }
2. 修复约束更新逻辑
修改外部高度约束的代理实现,更新约束后立即触发父视图布局,确保集合视图的渲染区域正常:
func collectionViewHeightDidChange(_ height: CGFloat) { self.collectionViewHeightConstraint.constant = height // 新增此行,立即生效约束变更 self.view.layoutIfNeeded() }
3. 调整集合视图刷新时序
修改reloadCollectionView方法,等待数据源刷新、布局计算完成后再更新高度,避免拿到未计算完成的contentSize:
func reloadCollectionView() { self.GIFCollectionView.reloadData() self.GIFCollectionView.collectionViewLayout.invalidateLayout() // 异步等待主队列布局计算完成后再获取contentSize DispatchQueue.main.async { self.GIFCollectionView.layoutIfNeeded() self.heightChanged() } }
4. 无元数据时的降级方案
如果接口确实没有返回GIF宽高,你可以预下载当前页所有GIF预览图,全部下载完成后再刷新集合视图:
// 在didFetchGIFsWithSuccess中新增预下载逻辑 func didFetchGIFsWithSuccess() { self.activityIndicator.stopAnimating() let group = DispatchGroup() guard let items = self.viewModel?.gifModel.items else { return } items.forEach { item in guard let url = item.previewGIFURL else { return } group.enter() SDWebImageManager.shared().loadImage(with: url, options: .lowPriority, progress: nil) { _, _, _, _, _, _ in group.leave() } } group.notify(queue: .main) { self.reloadCollectionView() } }
内容的提问来源于stack exchange,提问作者JFortYork
相关产品推荐
相关产品推荐

