我在收藏夹视图中遇到非常不稳定的滚动。只有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()
}
})
}
答案 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