0

I try to retrieve data from Firebase into Array. Because it runs asynchronously, the results that I want to show in my CollectionView is a delay until I switch back and forth. I am very new to asynchronous functions in iOS. Please help me to complete my code.

    ref = Database.database().reference(withPath: "MyTest/Video")
        ref?.observeSingleEvent(of: .value, with: { snapshot in

            if !snapshot.exists() { return }

            if let result = snapshot.children.allObjects as? [DataSnapshot] {
                for child in result {
                    let autoID = child.key as String //get autoID

                    let title = snapshot.childSnapshot(forPath: "\(autoID)/Title").value
                    let url = snapshot.childSnapshot(forPath: "\(autoID)/URL").value
                    let views = snapshot.childSnapshot(forPath: "\(autoID)/Views").value

                    self.arrayAllTitle.append(title as! String)
                    self.arrayAllId.append(url as! String)
                    self.arrayAllDesc.append(views as! String)
                }
            }


        })
3
  • 1
    You aren't actually calling reloadData() on your collection view once all values have been fetched from Firebase. After the for child in result{...} loop, you should do collectionView.reloadData(). Commented May 16, 2018 at 18:44
  • i did it, but it wasn't successfully :( Commented May 16, 2018 at 19:56
  • I fix it using completion approach. Thanks for your reply Commented May 16, 2018 at 21:53

2 Answers 2

1

You need to reload the collection after you retrieve the data so after the for loop call reloadData()

for child in result {

}

self.collectionView.reloadData()

//

func getValueFromDatabase(completion: @escaping (_ status: Bool) -> Void){

    ref = Database.database().reference(withPath: "MyTest/Video")
    ref?.observeSingleEvent(of: .value, with: { snapshot in

        if !snapshot.exists() { return }

        if let result = snapshot.children.allObjects as? [DataSnapshot] {
            for child in result {
                let autoID = child.key as String //get autoID

                let title = snapshot.childSnapshot(forPath: "\(autoID)/Title").value
                let url = snapshot.childSnapshot(forPath: "\(autoID)/URL").value
                let views = snapshot.childSnapshot(forPath: "\(autoID)/Views").value

                self.arrayAllTitle.append(title as! String)
                self.arrayAllId.append(url as! String)
                self.arrayAllDesc.append(views as! String)
            }

            completion(true)
        }
        else {
            completion(false)
        }
    })
}

//

self.getValueFromDatabase { (status) in

    if status {
       // success 
    }
 }
Sign up to request clarification or add additional context in comments.

5 Comments

How can we add "completion"? I read through many problems and it seems like they can use this approach. However, I'm not sure how to apply in within my code. I spent 2 days already fixing this problem. I would appreciate your help pls.
print works perfectly, but the collectionView still not showing anything.
did you set self.collectionView.dataSource = self
In viewDidLoad(), I call that function to add values into Arrays. However, collectionView only show results when I click back and forth.
Thanks a lot. Finally I fix my problem. You made it clear, but I couldn't figure it out at first, lolz..
0

I'm working with Firebase in my project right now. I would suggest the following solution: wrap the database observer in a distinct function which gets completion block as a parameter.

func getValueFromDatabase(completion: ()->Void){

    ref = Database.database().reference(withPath: "MyTest/Video")
    ref?.observeSingleEvent(of: .value, with: { snapshot in

        if !snapshot.exists() { return }

        if let result = snapshot.children.allObjects as? [DataSnapshot] {
            for child in result {
                let autoID = child.key as String //get autoID

                let title = snapshot.childSnapshot(forPath: "\(autoID)/Title").value
                let url = snapshot.childSnapshot(forPath: "\(autoID)/URL").value
                let views = snapshot.childSnapshot(forPath: "\(autoID)/Views").value

                self.arrayAllTitle.append(title as! String)
                self.arrayAllId.append(url as! String)
                self.arrayAllDesc.append(views as! String)
            }

            completion()
        }
    })
}

This way you can call the function from anywhere providing the desired action after fetching data from db is finished:

getValueFromDatabase(completion:{

    self.collectionView.reloadData() //or any other action you want to fulfil

})

2 Comments

I followed your approach. I create that function and call it in viewDidLoad() because I want to paste values into Arrays at the first time the app has loaded. It seems doesn't work. Did I do it right?
I fixed my problem and my code is working now. Thanks a lot :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.