如何从Firebase异步加载数据并将其显示在UICollectionView中

时间:2019-01-18 00:45:27

标签: swift firebase asynchronous firebase-realtime-database uicollectionview

我尝试显示登录用户关注的用户的用户名。仅详细描述那些在简单的UICollectionView中也有故事的人(例如Snapchat)。 因此,我需要在该单元格中将该人的用户名显示为简单标签。 为了做到这一点,我认为我可以简单地将所有带有故事的对象添加到Array中,然后再为第一个故事获取第一项,为第二个故事获取第二项,依此类推... 但是正如我之前提到的,我想检索并显示用户名。现在的问题是,“ cellForItemAt”函数没有等待从Firebase检索的数据填充该数组,因此它使用空的self.storyNames数组,并且return self.storyNames.count也等于到0。

class HomeViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {

    @IBOutlet weak var collectionView_stories: UICollectionView!

    var storyNames: [String] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        collectionView_stories.delegate = self
        collectionView_stories.dataSource = self
        collectionView_stories.showsHorizontalScrollIndicator = false

        getStoryNames() { storyNames in
            self.storyNames = storyNames
            DispatchQueue.main.async {
                self.collectionView_stories.reloadData()
            }
        }
    }

    @IBAction func barButton_camera_pressed(_ sender: Any) {
    }

    @IBAction func barButton_inbox_pressed(_ sender: Any) {
    }

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

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let story_cell = collectionView_stories.dequeueReusableCell(withReuseIdentifier: "stories_cell", for: indexPath) as? StoryCollectionViewCell

        story_cell?.imageView_story.layer.cornerRadius = (story_cell?.imageView_story.frame.size.width)! / 2
        story_cell?.imageView_story.clipsToBounds = true
        story_cell?.imageView_story.layer.shadowColor = UIColor.black.cgColor
        story_cell?.imageView_story.layer.shadowRadius = 3
        story_cell?.imageView_story.layer.shadowOpacity = 0.6
        story_cell?.imageView_story.layer.borderWidth = 1.0
        story_cell?.imageView_story.layer.borderColor = UIColor.darkGray.cgColor
        story_cell?.imageView_story.image = UIImage(named: "bitmoji")

        story_cell?.label_username.text = self.storyNames[indexPath.row]

        return story_cell!
    }

    func getStoryNames(completion: @escaping ([String]) -> ()) {
        var tempStoryNames: [String] = []
        let userID = Auth.auth().currentUser?.uid
        Database.database().reference().child("subscriptions").child(userID!).observeSingleEvent(of: .value) { snapshot in
            let dispatchGroup = DispatchGroup()
            for child in snapshot.children.allObjects as! [DataSnapshot] {
                let dict = child.value as! String
                Database.database().reference().child("users").child(dict).child("hasStory").observeSingleEvent(of: .value) { snapshot in
                    if let item = snapshot.value as? Bool {
                        if (item == true) {
                            dispatchGroup.enter()
                            Database.database().reference().child("users").child(dict).child("username").observeSingleEvent(of: .value) { snapshot in
                                let aaa = snapshot.value as! String
                                tempStoryNames.append(aaa)
                                print(tempStoryNames)
                            }
                        }
                    }
                    dispatchGroup.leave()
                }
            }
            dispatchGroup.notify(queue: .main) {
                completion(tempStoryNames)
            }
        }
    }
}

您知道如何解决此问题吗?我已经尽力了,也知道这不是最好的代码,但是我正在努力,因此我真的需要您的帮助。我感谢每个答案!

2 个答案:

答案 0 :(得分:0)

numberOfItemsInSection中,您应该取决于storyNames的长度,以确保您的数据将正确显示

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

答案 1 :(得分:0)

您如何了解并没有意义,因为cellForItemAt方法具有空的storyNames数组,因为如果storyNames.count为0,将永远无法到达cellForItemAt方法。仅在该部分中有多个项目时才调用CellForItemAt。

您可以在完成处理程序中放置一个断点,以查看是否返回了正确的storyName吗?

    getStoryNames() { storyNames in
        self.storyNames = storyNames // breakpoint here to see if actual data
        DispatchQueue.main.async {
            self.collectionView_stories.reloadData() // breakpoint here to see if storyNames still empty
        }
    }

如果确实调用了cellForItemAt方法,那么我认为您应该调试该方法。您从未注册过story_cell标识符,所以可能是这样吗?