UICollectionView swift 3延迟滚动UIImage

时间:2017-08-29 15:28:37

标签: swift swift3 uiimage native collectionview

我在收藏夹视图中遇到非常不稳定的滚动。只有10个细胞。这是因为我检索图像的方法是获取URL并将其转换为UIImage数据。

Images变量只是一个图像URL数组。

    public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return images.count
    }

    public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "mediaCells", for: indexPath) as! MediaCell
    let url = URL(string: images[indexPath.row] as! String)
    let data = try? Data(contentsOf: url!)
    cell.mediaImage.image = UIImage(data: data!)
    return cell
    }

我找到的解决方案是首先为所有图像执行此操作。这种方法的问题是它必须等待所有图像下载数据并在我们显示collectionView之前附加到数组。在我们渲染集合之前,这可能需要10到15秒的时间。太慢了!

    override func viewDidLoad() {
    super.viewDidLoad()
    Alamofire.request(URL(string: "myURL")!,
        method: .get)
        .responseJSON(completionHandler: {(response) -> Void in
            if let value = response.result.value{
                let json = JSON(value).arrayValue
                for item in json{
                    let url = URL(string: item["image"].string!)
                    let data = try? Data(contentsOf: url!)
                    self.images.append(data)
                }
                self.collectionView.reloadData()
        }
    })
    }

4 个答案:

答案 0 :(得分:0)

使用cocoapods的SDWebImage进行异步图像提取。

https://cocoapods.org/?q=SDWebImage

cell.mediaImage.sd_setImage(with: URL(string: images[indexPath.row] as! String))

答案 1 :(得分:0)

有人会对全局变量的使用大喊大叫,但这是我之前的做法:

声明UIImage的全局数组

var images: [UIImage] = []

下载图片后,将其附加到该阵列

for item in json{
        let url = URL(string: item["image"].string!)
        let data = try? Data(contentsOf: url!)
        let image = UIImage(data: data!)
        images.append(image)
        NotificationCenter.default.post(Notification.Name(rawValue: "gotImage"), nil)
}

按照VC中的通知

override function viewDidLoad() {
    NotificationCenter.default.addObserver(self, selector: #selector(collectionView.reloadData()), name: NSNotification.Name(rawValue: "gotImage"), object: nil)
    super.viewDidLoad()
}

如果您的单元格中没有可用于collectionView

,请不要指定图像
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
     .....
     if let image = images[indexPath].row {
          cell.mediaImage.image = image
     }
     ....
}

PS:如果所有下载和加载操作都发生在同一个VC中,只需在VC类中声明images即可。

答案 2 :(得分:0)

好像你需要根据可见单元格在集合视图中进行延迟加载图像。我已经实现了这样的方法。

1)首先需要创建一个名为PendingOperations.swift的类

class PendingOperations {
 lazy var downloadsInProgress = [IndexPath: Operation]()
 lazy var downloadQueue: OperationQueue = {
 var queue = OperationQueue()
 queue.name = "downloadQueue"
 queue.maxConcurrentOperationCount = 1
 return queue
 }()
}

2)第二步创建一个名为ImageDownloader的类,您可以在其中进行网络调用以下载图像。

class ImageDownloader: Operation {
 let imageId: String
 init(imageId: String) {
  self.imageId = imageId
 }
 override func main() {
  if self.isCancelled {
   return
  }
 Alamofire.request(URL(string: "myURL")!,
        method: .get)
        .responseJSON(completionHandler: {(response) -> Void in
            if let value = response.result.value{
                let json = JSON(value).arrayValue
                for item in json{
                    let url = URL(string: item["image"].string!)
                    self.image = try? Data(contentsOf: url!)
 })
 if self.isCancelled {
   return
     }
  }
}

3)第三步在viewController中实现一些方法,以根据可见单元格操作操作。

func startDownload(_ image: imageId, indexPath: IndexPath) {
 if let _ = pendingOperations.downloadsInProgress[indexPath] {
    return
 }
 let downloader = ImageDownloader(image: imageId)
 downloader.completionBlock = {
  if downloader.isCancelled {
   return
   }
}
 pendingOperations.downloadsInProgress.removeValue(forKey: indexPath)
 pendingOperations.downloadsInProgress[indexPath] = downloader
 pendingOperations.downloadQueue.addOperation(downloader)
 }
}

func suspendAllOperation() {
 pendingOperations.downloadQueue.isSuspended = true
}

func resumeAllOperation() {
  pendingOperations.downloadQueue.isSuspended = false
}

func loadImages() {
 let pathArray = collectionView.indexPathsForVisibleItems
 let allPendingOperations = 
 Set(Array(pendingOperations.downloadsInProgress.keys))
 let visiblePath = Set(pathArray!)
 var cancelOperation = allPendingOperations
 cancelOperation.subtract(visiblePath)
 var startOperation = visiblePath
 startOperation.subtract(allPendingOperations)
for indexpath in cancelOperation {
    if let pendingDownload = 
 pendingOperations.downloadsInProgress[indexpath] {
 pendingDownload.cancel()
}
 pendingOperations.downloadsInProgress.removeValue(forKey: indexpath)
}
 for indexpath in startOperation {
    let indexPath = indexpath
    startDownload(imageId, indexPath: indexPath)
}
}

4)实现scrollView委托方法的第四步。

func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        suspendAllOperation()
    }

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    loadImages()
    resumeAllOperation()
}

func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    if !decelerate {
        loadImages()
        resumeAllOperation()
    }
}

func clearImageDownloaderOperations() {
    if pendingOperations.downloadsInProgress.count > 0 {
        pendingOperations.downloadsInProgress.removeAll()
        pendingOperations.downloadQueue.cancelAllOperations()
    }
}

答案 3 :(得分:0)

使用Kingfisher 5来预取,加载,显示和缓存图像,我们可以解决此问题。

let url = URL(fileURLWithPath: path)
let provider = LocalFileImageDataProvider(fileURL: url)
imageView.kf.setImage(with: provider)

https://github.com/onevcat/Kingfisher/wiki/Cheat-Sheet#image-from-local-file