来自调试器的消息:在 UITableView/UICollectionView 中使用 gif 图像 Kingfisher 库滚动时因内存问题而终止
Posted
技术标签:
【中文标题】来自调试器的消息:在 UITableView/UICollectionView 中使用 gif 图像 Kingfisher 库滚动时因内存问题而终止【英文标题】:Message from debugger: Terminated due to memory issue While scrolling in UITableView/UICollectionView with gif images Kingfisher Library 【发布时间】:2019-03-01 07:56:12 【问题描述】:代码sn-p:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let cell: BroadCastFeedTableViewCell = broadCastTableView.dequeueReusableCell(withIdentifier: "broadCastFeedCell") as BroadCastFeedTableViewCell
cell.singlePicImageView.kf.setImage(with: URL(string: (self.broadCastArray[indexPath.row].images_url?[0])!), placeholder: nil, options: nil, progressBlock: nil)
(theImage, error, cache, url) in
if theImage != nil
let imageHeight = self.getAspectRatioOfDownloadedImages(resolution: self.broadCastArray[indexPath.row].image_resolution![0])
cell.collectionContentViewHeightConstraint.constant = imageHeight
cell.layoutSubviews()
cell.layoutIfNeeded()
else
let placeHolderCenterCordi = UIView().getViewRelationWithSuperSuperView(viewControllerView: cell.collectionContentView,
subView: cell.singlePicImageView, subObjFrame: cell.singlePicImageView.frame)
cell.singlePicImageView.addPlaceHolderImageView(cordinates: placeHolderCenterCordi.center)
self.broadCastTableView.rowHeight = UITableViewAutomaticDimension
在上面的代码中,我使用 Kingfisher 库从远程服务器加载图像,每当以下代码加载某些可能具有大尺寸(大约 2-5 MB)的图像(GIF、JPEG、PNG)时,应用程序由于内存而终止问题。在 iPhone 5s 中,它会在应用程序启动后立即终止,而在其他 iPhone 型号(7、6s)中,它会在滚动一定时间后终止。我也检查了分配和泄漏,但我对这个问题不太了解/发现。
我还附上了分析图。这表明没有此类内存泄漏,但由于某些问题,应用程序正在终止:
【问题讨论】:
【参考方案1】:我在内存加载图像时遇到了很多问题。我不能确定你的情况,但我可以给你一些有用的提示。
-
查看 UITableViewDataSourcePrefetching。这是一种在图像在单元格中呈现之前下载图像的方法。
考虑在某处创建一个 Helper 函数来开始下载并允许取消下载。例如,当您快速向下滚动表格视图时,每个单元格都将开始下载图像,即使它没有显示。如果单元格消失,您可以取消下载。
单元格基本上应该是代码中的 UI 元素。这个想法是,尝试从单元格本身中取出网络请求,并确保您的单元格只包含要呈现的元素(图像、标签、视图),单元格具有 func configure(withModel: Model) 函数,并且在 cellForRow 上,您只需将数据传递给它进行渲染。单元被重复使用和频繁更新,你不应该在它上面执行一堆东西。请记住,当一个单元格被加载时,它会调用这些函数,然后它可以离开屏幕并再次返回,它会重新执行所有这些操作。
您的单元格类是否执行了正确的布局更新和刷新,并尽量不在 cellForRow 中执行此操作。您所能做的只是确保 imageview 获取图像,而不是依赖于执行单元格更改,并且此图像下载是异步的,下载结束时该单元格甚至可能不存在。
缓存。您可以缓存这些图像还是它们不断变化?确保您了解 KF 是如何缓存您的图像的,并且正在执行您需要的缓存。如果没有,请适应。
[挑剔] 你打电话给
cell.layoutSubviews()
然后cell.layoutIfNeeded()
。第一个是强制调用layoutSubviews,第二个是在调用layoutSubView之前检查是否有需要布局的东西。如果要标记要布局的视图,可以执行 setNeedsLayout()。这将使视图布局在下一个周期更新。
【讨论】:
不错。会有帮助【参考方案2】:我认为在您的代码中,您使用“Self”作为强项,因此它会创建一个强引用循环,因为这会造成内存泄漏。所以此时你可以尝试使用 [weak self] 而不是运行你的代码
cell.singlePicImageView.kf.setImage(with: URL(string: (self.broadCastArray[indexPath.row].images_url?[0])!), placeholder: nil, options: nil, progressBlock: nil)
[weak self] (theImage, error, cache, url) in
if theImage != nil
let imageHeight = self?.getAspectRatioOfDownloadedImages(resolution: self?.broadCastArray[indexPath.row].image_resolution![0])
cell.collectionContentViewHeightConstraint.constant = imageHeight
cell.layoutSubviews()
cell.layoutIfNeeded()
else
let placeHolderCenterCordi = UIView().getViewRelationWithSuperSuperView(viewControllerView: cell.collectionContentView,
subView: cell.singlePicImageView, subObjFrame: cell.singlePicImageView.frame)
cell.singlePicImageView.addPlaceHolderImageView(cordinates: placeHolderCenterCordi.center)
self?.broadCastTableView.rowHeight = UITableViewAutomaticDimension
【讨论】:
没有兄弟没有内存泄漏,查看附件的profiling图片【参考方案3】:回答我自己的问题
以下对我有用
我为我的翠鸟库提供的 UIImageView 使用了 AnimatedImageView 类
let imageView = AnimatedImageView()
imageView.kf.setImage(with: URL(string: "your_image"), placeholder: nil, options: [.targetCache(ImageCache(name: "your_cache_name")), .backgroundDecode], progressBlock: nil) (image, error, cache, url) in
// some code
注意事项
[.targetCache(ImageCache(name: "your_cache_name")), .backgroundDecode]
在上面的 options 属性代码中,我使用了自己的缓存 (ImageCache(name: "your_cache_name")) 并要求 kingfisher 在后台解码图像
【讨论】:
以上是关于来自调试器的消息:在 UITableView/UICollectionView 中使用 gif 图像 Kingfisher 库滚动时因内存问题而终止的主要内容,如果未能解决你的问题,请参考以下文章
退出应用程序会导致错误“来自调试器的消息:由于信号 9 而终止”
来自调试器的消息:在 UITableView/UICollectionView 中使用 gif 图像 Kingfisher 库滚动时因内存问题而终止