来自调试器的消息:在 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 库滚动时因内存问题而终止的主要内容,如果未能解决你的问题,请参考以下文章

来自 C 代码的 NSLog 样式调试消息

退出应用程序会导致错误“来自调试器的消息:由于信号 9 而终止”

来自调试器的消息:在 UITableView/UICollectionView 中使用 gif 图像 Kingfisher 库滚动时因内存问题而终止

来自调试器的消息:由于内存问题而终止

来自调试器的消息:由于信号 9 而终止 - 有没有办法运行后台操作?

获取“来自调试器的消息:错误 1” - 用于简单项目(在 Xcode 11.0 11A420a 中)[重复]