更新图片后UITableView单元格无法自动刷新的问题
问题分析与解决方案
先拆解你遇到的两个核心问题:图片下载后无法自动显示、调用reloadData()导致应用冻结,咱们一步步来解决。
一、图片无法自动显示的根本原因
看你InventoryListView.swift里的代码,发现两个关键错误:
- UI控件引用错误:你自定义cell的IBOutlet是
assetImageView,但图片下载完成后,你给self.imageView?.image赋值——这是UITableViewCell默认的系统imageView,不是你界面上拖的那个!图片其实已经下载了,但没显示到正确的控件上。 - 后台线程操作UI:Firebase Storage的
getData回调是在后台线程执行的,直接在闭包里修改UI元素会导致更新不及时,必须切换到主队列操作。
二、调用reloadData()导致应用冻结的原因
如果在每个图片下载完成的闭包里调用reloadData(),会导致表格频繁刷新(每下载一张图片就刷新一次),加上cell复用的逻辑,会造成大量重复操作,直接把CPU拉满,应用自然就冻结了。
修复方案(分步实施)
1. 修正UI控件引用与线程问题
先把InventoryListView.swift里的图片赋值代码改对,并且切换到主队列:
// 在pathRef.getData的闭包else分支里修改 pathRef.getData(maxSize: 1 * 1024 * 1024) { (data, err) in if let err = err { print(err) return } // 切换到主队列操作UI DispatchQueue.main.async { let assetImage = UIImage(data: data!) inventoryAsset.assetImage = assetImage // 这里改成你的自定义ImageView self.assetImageView.image = assetImage } }
2. 优化图片下载逻辑,避免重复请求与频繁刷新
当前在cellForRowAt里每次创建cell时都调用setInventoryCell下载图片,会导致cell复用时重复发起下载请求,不仅浪费带宽,还会导致图片显示混乱。我们可以做两个优化:
(1)给Asset模型增加图片缓存状态
先在你的Asset模型里加一个标记,判断图片是否已经下载过:
class Asset { // 你的其他属性... var assetImage: UIImage? var isImageDownloaded: Bool = false // 新增下载状态标记 }
(2)只在图片未下载时发起请求
修改setInventoryCell里的下载逻辑:
func setInventoryCell(_ inventoryAsset:Asset) { // 先判断图片是否已经下载过,避免重复请求 if let image = inventoryAsset.assetImage { self.assetImageView.image = image return } // 再判断是否有有效图片URL guard let imageURL = inventoryAsset.assetImageURL, !imageURL.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { self.assetImageView.image = nil // 没有URL时清空图片 return } // 发起下载请求 let storage = Storage.storage() let pathRef = storage.reference(forURL: imageURL) pathRef.getData(maxSize: 1 * 1024 * 1024) { (data, err) in if let err = err { print(err) return } DispatchQueue.main.async { let assetImage = UIImage(data: data!) inventoryAsset.assetImage = assetImage inventoryAsset.isImageDownloaded = true self.assetImageView.image = assetImage } } // 其他文本赋值逻辑不变... }
3. 可选:使用图片加载库简化逻辑
如果不想自己处理缓存和线程问题,可以用成熟的第三方库,比如SDWebImage(支持Firebase Storage直接加载),只需要一行代码就能搞定:
// 先导入SDWebImage import SDWebImage // 在setInventoryCell里替换下载逻辑 func setInventoryCell(_ inventoryAsset:Asset) { if let imageURL = inventoryAsset.assetImageURL, !imageURL.isEmpty { let pathRef = Storage.storage().reference(forURL: imageURL) // SDWebImage会自动处理缓存、线程、复用问题 self.assetImageView.sd_setImage(with: pathRef) } else { self.assetImageView.image = nil } // 其他文本赋值逻辑不变... }
验证效果
修改后,你会发现图片下载完成后会自动显示在对应的cell里,不需要手动点击刷新表格。而且因为避免了重复请求和频繁刷新,CPU占用也会恢复正常。
内容的提问来源于stack exchange,提问作者Tyler Wasick
相关产品推荐
相关产品推荐

