使Completionhandler在For-Loop中工作以进行图像提取

时间:2019-05-03 20:14:39

标签: swift firebase for-loop closures completionhandler

我正在从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")
            })
        }
    }

1 个答案:

答案 0 :(得分:0)

问题是您有嵌套的闭包,因此在调用时:

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(),这取决于您的需要,但是您可以根据需要提取图像,将图像设置为单元格内容时,调用提取图像(首先从缓存中获取图像,如果不可用则下载),然后仅更新图像的显示位置。 这样,您的应用程序将更动态地显示在屏幕上,还可以设置占位符图像。