【问题标题】:Make Completionhandler Work in For-Loop for Image Fetching使 Completionhandler 在 For 循环中工作以获取图像
【发布时间】:2019-05-03 20:14:39
【问题描述】:

我正在从 Firebase 获取用户图片。一个用户最多可以在数据库中上传 6 张图像。我想以正确的顺序(0-6)将图像下载到 CollectionView 中。

当我尝试使用 CompletionHandler 时,它无法按我的意愿工作。 CollectionView 的重新加载在获取图像之前很久就完成了,没有显示图像,因为图像是在调用 reloadData 之后放入数组中的。

不胜感激有关此问题的帮助。

这是我的代码:

override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        downloadAndReload()
    }

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

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "swipeCell", for: indexPath as IndexPath) as! ProfileCardCollectionViewCell
        let image = self.arrayImages[indexPath.item]
        cell.swipeProfileImage.image = image
        print("lägger ut cell")
        return cell
    }

    func downloadAndReload(){
        cachedImage(completion: { message in
            print(message)
            self.swipeCollectionView.reloadData()
        })
    }


    func cachedImage(completion: @escaping (_ message: String) -> Void){
        if let uid = Auth.auth().currentUser?.uid{
            for i in 0...6{

                let url = URL(string: uid+String(i))

                SDWebImageManager.shared.loadImage(with: url, options: .refreshCached, progress: .none ,completed: { (image, data, error, _, _, _) in

                    if let error = error{
                        print("Couldn't download image")
                        self.downloadImage(i: i, completion: {_ in

                        })
                    }
                    else{
                        print("Could download image")
                        self.arrayImages.append(image!)
                    }
                })
            }
            completion("DONE")
        }

    }

    func downloadImage(i: Int, completion: @escaping (_ fetchWorked: String) -> Void){
        print("Downloading Image")

        let g = DispatchGroup()
        g.enter()
        if let uid = Auth.auth().currentUser?.uid{
            let imagesStorageRef = Storage.storage().reference().child("profilepic/").child(uid+String(i))

            imagesStorageRef.downloadURL { url, error in
                guard let url = url else { return }

                SDWebImageManager.shared.loadImage(with: url, options: .refreshCached, progress: .none ,completed: { (image, data, error, _, _, _) in

                    if let error = error{
                    }
                    else{
                        self.arrayImages.append(image!)
                    }
                })

                g.leave()

            }
            g.notify(queue: .main, execute: {
                completion("Done")
            })
        }
    }

【问题讨论】:

    标签: swift firebase for-loop closures completionhandler


    【解决方案1】:

    问题是你有嵌套的闭包,所以当你调用时:

    SDWebImageManager.shared.loadImage(with: url, options: .refreshCached, progress: .none ,completed: { (image, data, error, _, _, _) in
    
                    if let error = error{
                        print("Couldn't download image")
                        self.downloadImage(i: i, completion: {_ in
    
                        })
                    else{
                        print("Could download image")
                        self.arrayImages.append(image!)
                    }
                })
    

    其中的所有内容只有在“loadImage”完成时才会被调用,因此你的“for”将调用“SDWebImageManager.shared.loadImage”6次,然后调用“completion(“Done”)”。

    因此您的代码将在处理完图像之前调用“completion("Done")”,因此在没有图像或可能有图像时重新加载数据。

    在调用 reloadData() 之前,您需要等待获取完成,这取决于您的需要,但您可以根据需要获取图像,当您要将图像设置为单元格内容时,调用获取图像(首先从缓存或下载,如果不可用)然后只更新它们的显示位置。 这样,您的应用程序将在屏幕上更加动态地显示,同时设置占位符图像。

    【讨论】:

    • 谢谢,问题是 CollectionView 需要知道 arrayImages.count 有多大。我只希望上传的图像显示在单元格中。这就是为什么我想在重新加载之前先下载所有图像。
    • 但是在您的代码中,它被硬编码为始终为 6,如果您知道它始终为 6,则它是一个固定值。请记住 Facebook 和 Instagram 的情况,它们不一定会显示所有图像,它们会按需加载,然后在加载图像时更新大小(单元格数量)。如果您想先下载它们,那么最好在呈现视图之前调用该函数,但这取决于您的应用程序的结构(
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-08
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多