在 CollectionView 中使用 SDWebImage 的疯狂内存问题(在 tableviewCell 内)

Posted

技术标签:

【中文标题】在 CollectionView 中使用 SDWebImage 的疯狂内存问题(在 tableviewCell 内)【英文标题】:Crazy Memory Issues using SDWebImage in a CollectionView (inside a tableviewCell) 【发布时间】:2019-02-21 20:58:53 【问题描述】:

当我开始滚动带有由 SDWebImage 填充的图像视图的集合视图时,我无法弄清楚为什么我的应用程序的内存会迅速增加。如果它们还没有下载,那么一段时间就可以了。但是一旦下载了每张图片,如果我什至触摸滚动条,应用程序 ui 就会变得无响应并且内存猛增(超过 1GB),以至于不仅应用程序崩溃,整个操作系统也崩溃并重新启动。

我有一个包含几个单元格的 tableview,其中一个有一个可以滚动的 collectionview。我有一个数据对象,用于填充 collectionViewCell 中的所有标签和图像。 cellForItem 非常复杂(很多 if 语句和 switch 语句),所以我尝试将一些代码从那里移出,并将其移至我在 collectionViewCell 中设置的属性的 didSet 方法以保存数据对象。然后我只是将数据对象设置为 itemForRow 中的属性(在后台线程中),它触发了单个 collectionViewCell 的 didSet 方法来填充标签并使用 sd_set_image 方法设置图像。下面是tableViewCell上的相关代码:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
print(indexPath.row)
if itemStyle == .Grid 

  let cell = collectionView.dequeueReusableCell(withReuseIdentifier: self.resourceCellIdentifier, for: indexPath) as! ResourceCollectionViewCell
  cell.delegate = self
  cell.tag = indexPath.row

  if self.filter == Filter.Collections ||  self.resourceArray?[indexPath.row].actionContent == nil 
    let resource: ActionContentTemplate?
    if self.filter == Filter.Collections 
      resource = self.collectionResourceArray?[indexPath.row].actionContentTemplate
     else 
      resource = self.resourceArray?[indexPath.row].actionContentTemplate
    

    DispatchQueue.global(qos: .userInitiated).async 

      cell.dataObject = resource
    
    return cell

   else .....

这是 CollectionViewCell 本身的 didSet 方法:

var dataObject: ActionContentTemplate? 
didSet 
  var cellRow: Int = 0

  if self.actionContentTemplate != nil 
    ....

    DispatchQueue.main.async 
      cellRow = self.tag

       .....

      switch self.actionContentTemplate?.contentTypeID?.uintValue 
      case ContentTypeVideo.rawValue,
           ContentTypeVideoRecording.rawValue,
           ContentTypeScreenRecording.rawValue:
        .......
      case ContentTypeAttachment.rawValue:


        let fileType = (self.actionContentTemplate?.contentFileName as NSString?)?.pathExtension.lowercased()
        var placeholderImage: UIImage

        if fileType == "pdf" 
          placeholderImage = UIImage(named: "pdf")!
         else if fileType == "doc" 
          placeholderImage = UIImage(named: "doc")!
         else if fileType == "docx" 
          placeholderImage = UIImage(named: "doc")!
         else if fileType == "xls" 
          placeholderImage = UIImage(named: "xls")!
         else if fileType == "xlsx" 
          placeholderImage = UIImage(named: "xls")!
         else if fileType == "ppt" 
          placeholderImage = UIImage(named: "ppt")!
         else if fileType == "pptx" 
          placeholderImage = UIImage(named: "ppt")!
         else 
          placeholderImage = UIImage(named: "plain")!
        

        if let urlString = self.actionContentTemplate?.thumbnailURL 
          let imageURL = URL(string: urlString)

          SDWebImageManager.shared().loadImage(with: imageURL, options: [.continueInBackground, .scaleDownLargeImages], progress: nil)  (image, data, err, cacheType, finished, url) in
              DispatchQueue.main.async 
                if cellRow == self.tag 

                self.activityIndicator?.stopAnimating()
                self.imageView.image = image
                UIAnimation.fadeTransitionImageView(self.imageView)
              
            
          
                      

         else 
          DispatchQueue.main.async 

            self.activityIndicator?.stopAnimating()
            self.imageView.image = placeholderImage
          
        
        break
.....

我实际上切换到 loadImage 方法,因为 sd_setimage 方法也不起作用。

 SDWebImageManager.shared().loadImage(with: imageURL, options: [.continueInBackground, .scaleDownLargeImages], progress: nil)  (image, data, err, cacheType, finished, url) in
                  DispatchQueue.main.async 
                    if cellRow == self.tag 
//IF I COMMENT OUT THESE TWO LINES BELOW THE ISSUES STOP (I think it is only the self.imageView.image = image line that is causing issues)
         //           self.activityIndicator?.stopAnimating()
         //           self.imageView.image = image
                    UIAnimation.fadeTransitionImageView(self.imageView)
                  
                
              

谁能向我解释为什么会发生这种情况以及我可以做些什么来解决它?

编辑 - 忘记在应用委托中添加这些设置来提问:

//Settings for image caching
  [[SDWebImageDownloader sharedDownloader] setShouldDecompressImages:NO];

  [[[SDImageCache sharedImageCache] config] setShouldDecompressImages:NO];
  [[[SDImageCache sharedImageCache] config] setShouldCacheImagesInMemory:NO];
  [[[SDImageCache sharedImageCache] config] setMaxCacheSize:1024 * 1024 * 100];
  [[[SDImageCache sharedImageCache] config] setMaxCacheAge:3600 * 24 * 7];
  [[SDImageCache sharedImageCache] setMaxMemoryCost:1024 * 1024 * 15];

【问题讨论】:

【参考方案1】:

原来缩略图相当大,使用此链接 (ios Swift: How to properly scale down an image?) 将图像调整为 imageView 大小完全解决了内存问题。然而,图像下载后滚动有点不稳定......我认为将尽可能多的计算代码移动到后台线程并移出 cellForItem 会有所帮助,但我显然错过了一些东西。如果有人能指出我正确的方向,那将不胜感激,因为作为开发人员,我一直在努力学习更多知识。

【讨论】:

以上是关于在 CollectionView 中使用 SDWebImage 的疯狂内存问题(在 tableviewCell 内)的主要内容,如果未能解决你的问题,请参考以下文章

在带有 xib 文件的 UIView 中使用 CollectionView

如何在所有设备中使用 swift4 在 CollectionView 中显示两列

CollectionView 中的 CollectionView:使用 didSelectItemAt 执行Segue

在 Swift 3 中使用 CGSize 的 collectionView 的 100% 宽度

如何在 Swift 中使用宽度约束将 Xib 加载到 CollectionView?

如何使用更少的内存在 collectionView 中显示照片库