Swift:异步加载和显示照片 [英] Swift: asynchronously loading and displaying photos

查看:315
本文介绍了Swift:异步加载和显示照片的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为从iPhone到collectionView的相册显示问题而苦苦挣扎.

I'm struggling with the problem of displaying photo gallery from iPhone to collectionView.

如果某人在画廊中拥有50张照片,那么一切都会很好.问题是,当某人有数千张照片时,图库会加载10秒钟,这对我的应用程序不利.
当我从Facebook加载图像时,会发生相同的问题.该应用程序正在等待,直到它下载了每张照片,然后显示出来.我想在加载过程中一张一张地显示图像,而不是等待它全部加载.

Everything works fine if someone has 50 photos inside the gallery. The problem is when someone has thousands of photos, then the gallery is loading for 10 seconds, which is not good for my app.
The same problem occurs when I'm loading images from Facebook. The app is waits until it downloads every photo then it displays. I'd like to display images one by one during the loading operation instead of waiting for it to load it all.

我知道我应该使用DispachQueue,并且确实使用过,但是有一些我看不到的错误.
这是我用来从iPhone图库中获取图像的代码:

I know that I should use DispachQueue and I did but there is some bug that I don't see.
Here is the code I use to fetch images from iPhone gallery:

func grapPhotos() {
    let imgManager = PHImageManager.default()
    let requestOptions = PHImageRequestOptions()
    requestOptions.isSynchronous = true
    requestOptions.deliveryMode = .highQualityFormat
    let fetchOptions = PHFetchOptions()

    fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]

    if let fetchResulat : PHFetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions) {

        if fetchResulat.count > 0 {

            for i in 0..<fetchResulat.count {

                imgManager.requestImage(for: fetchResulat.object(at: i), targetSize: CGSize(width: 200, height:200), contentMode: PHImageContentMode.aspectFill, options: requestOptions, resultHandler: {
                    (image, eror) in

                    self.imageArray.append(image!)

                    DispatchQueue.main.async {
                        self.collectionView.reloadData()
                    }
                })
            }
        } else {

            print("You have no photos")
            self.collectionView.reloadData()
        }
    }
}

以及在collectionView中显示它们的代码:

And the code to display them in collectionView:

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

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "galleryCell", for: indexPath) as! GalleryCollectionViewCell

        let image = self.imageArray[indexPath.row]

        DispatchQueue.main.async {
            cell.gelleryImages.image = image
            }

    return cell
}

我的Facebook课上可能存在相同的问题,所以我将非常感谢您的帮助.

Probably the same problem is with my Facebook class so I will be very grateful for your help.

推荐答案

您需要的是向集合视图控制器中添加fetchResult属性,并在viewDidLoad方法中获取图像Assets.

What you need is to add a fetchResult property to your collection view controller and fetch your image Assets inside viewDidLoad method.

var fetchResult: PHFetchResult<PHAsset> = PHFetchResult()

func fetchAssets() {
    let fetchOptions = PHFetchOptions()
    fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
    fetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions)
}

override func viewDidLoad() {
    super.viewDidLoad()
    fetchAssets()
}

下一步是扩展UIImageView,以请求图像数据在完成时异步设置其图像.

Next step is extend UIImageView to request the image data asynchronously setting its image on completion.

extension UIImageView {    
    func fetchImage(asset: PHAsset, contentMode: PHImageContentMode, targetSize: CGSize, version:  PHImageRequestOptionsVersion = .current, deliveryMode: PHImageRequestOptionsDeliveryMode = .opportunistic) {
        let options = PHImageRequestOptions()
        options.version = version
        options.deliveryMode = deliveryMode
        PHImageManager.default().requestImage(for: asset, targetSize: targetSize, contentMode: contentMode, options: options) { image, _ in
            guard let image = image else { return }
            switch contentMode {
            case .aspectFill: self.contentMode = .scaleAspectFill
            case .aspectFit:  self.contentMode = .scaleAspectFit
            @unknown default: fatalError()
            }
            self.image = image
        }
    }
}

现在,您可以一次在集合视图cellForItemAt方法中获取一张图像:

Now you can fetch the images one at a time inside collection view cellForItemAt method:

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! CollectionViewCell
    let asset = fetchResult.object(at: indexPath.row)
    cell.imageView.fetchImage(asset: asset, contentMode: .aspectFill, targetSize: cell.imageView.frame.size * UIScreen.main.scale )
    return cell
}

别忘了返回numberOfItemsInSection方法的fetchResult计数.

Don't forget to return the fetchResult count for numberOfItemsInSection method.

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


class CollectionViewCell: UICollectionViewCell {
    @IBOutlet weak var imageView: UIImageView!
}


extension CGSize {
    static func *(lhs: CGSize, rhs: CGFloat) -> CGSize {
        .init(width: lhs.width * rhs, height: lhs.height * rhs)
    }
}

这篇关于Swift:异步加载和显示照片的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆