0

I am new to swift and developing my first application. In my application there is a collection view on which I want to display images. These images are retrieved from Firebase Database.

The structure for Firebase Database is as follows

{
  "CHILD1" : {
    "URL1" : "https://Child1_url1.com",
    "URL2" : "https://Child1_url2.com",
    "URL3" : "https://Child1_url3.com"
  }
  "CHILD2" : {
    "URL1" : "https://Child2_url1.com",
    "URL2" : "https://Child2_url2.com",
  }
  "CHILD3" : {
    "URL1" : "https://Child3_url1.com",

  }

}

To retrieve urls I am using below code

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

func checkSectionCount(){
    Database.database().reference().observe(.value) { (snapShot: DataSnapshot) in

        let snapDict = snapShot.value as? NSDictionary
        let snapCnt = String(snapDict!.count)
        print("snapCnt --> \(snapCnt)")// This prints the number of child counts correctly

    }
 }

 func numberOfSections(in collectionView: UICollectionView) -> Int {
    return snapCnt //I am unable to refer the snapCnt to set the number of section dynamically here

}

As indicated in above code, I am unable to refer snapCnt out of func checkSectionCount. I also tried to return this value as function parameter however swift is unable to identify snapCnt out of

Database.database().reference(){ Code

}

Not sure what I am missing here. Appreciate if anyone can guide me through this on how to dynamically set the section and row numbers for collection view based on the details available in Firebase Database.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
AppsBuff
  • 3
  • 2

2 Answers2

0

Data is loaded from Firebase asynchronously, since it may take some time for it to come back from the server. Instead of blocking your code (and making the app unresponsive), the main code continues to run. Then when the code comes back from the server, the completion handler is called.

It's easiest to see this if you change your code and add some logging statements:

print("Before starting to get data")
Database.database().reference().observe(.value) { (snapShot: DataSnapshot) in
    print("Got data")
}
print("After starting to get data")

When you run this code, it prints:

Before starting to get data

After starting to get data

Got data

This is probably not the order that you expected, although it is the normal and documented behavior.

For this reason any code that needs the data from the database must be inside the completion handler, or be called from there.

For some more examples of how to deal with this, see:

Community
  • 1
  • 1
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
0

Alright, with help of links shared by @Frank i could resolve the issue. Below is the approach i took, which worked for me.

Step1: Created func with escaping completion handler

func getServiceTypeCount(completion: @escaping (Int) -> Int){
    dbRef.child("Services").observeSingleEvent(of: .value) { (serviceDataSnapshot) in
        let snapShot = serviceDataSnapshot.value as? [String: Any] ?? [:]
        let serviceTypeCount = completion(Int(snapShot.count))

    }
}

Step2: Called this function in viewDidLoad()

getServiceTypeCount { serviceTypeCount in
        self.finalServiceTypeCount = serviceTypeCount
        DispatchQueue.main.async {
            self.newClassesTableVw.reloadData()
        }
        return self.finalServiceTypeCount
    }

Note that i have added DispatchQueue.main.async to reload the table. That was to refresh the table with proper count value

Step3: Added the count value to display sections

func numberOfSections(in tableView: UITableView) -> Int {
    return self.finalServiceTypeCount
}

Hope this helps, Thanks.

Regards.

AppsBuff
  • 3
  • 2