How to Make Uicollectionview Reload Once It Receives Data from Firebase

How to make uicollectionview reload once it receives data from firebase?

You need to call self.collectionView!.reloadData() after you have retrieved you data and stored it into your DataSource.

i.e in your completionBlock: of your Firebase .observeSingleEventOfType

databaseRef.child("users").child(userID!).child("medals").observeSingleEventOfType(.Value, withBlock: { (snapshot) in
// Get user medals
self.identities3 = snapshot.value as! [String]
self.collectionView!.reloadData()
})

How should I retrieve data to the UICollectionViewCell from Firebase?

Reading through the comments it appears you are asking how to read data from Firebase. Since there's no Firebase code in the question, I'm having to guess what you ultimately want to accomplish so I would first direct you to the Firebase Guide Reading and Writing Data as that covers the topic. Then, see Working With Lists

To provide a leg up, here's one possible solution.

Since you have a tableView, that would usually be backed by a tableView datasource. So the concept is to read the data from Firebase and then populate that datasource, then refresh the tableView which will show the objects to the user in the UI.

Let's start with a class to hold the data from Firebase Realtime Database

class ProgramClass {
var description = ""
var image = ""
var title = ""

init(withSnapshot: DataSnapshot) {
self.description = withSnapshot.childSnapshot(forPath: "description").value as? String ?? "No Description"
self.image = withSnapshot.childSnapshot(forPath: "image").value as? String ?? "No Image"
self.title = withSnapshot.childSnapshot(forPath: "title").value as? String ?? "No Title"
}
}

and then a class var to hold those objects

var programsArrayDataSource = [ProgramClass]()

keep in mind that class var will act as the dataSource which backs your tableview. When a change occurs in firebase, the dataSource would be updated via Firebase observe (.childAdded, .childChanged or .childRemoved) and then the tableView reloaded.

To actually read the Firebase structure presented in your question, use the following code. This will both read Firebase as well as populating the dataSource for your tableView.

func fetchPrograms() {
let programsRef = self.ref.child("programs")
programsRef.observeSingleEvent(of: .value, with: { snapshot in
let allPrograms = snapshot.children.allObjects as! [DataSnapshot]
for programSnap in allPrograms {
let aProgram = ProgramClass(withSnapshot: programSnap)
self.programsArrayDataSource.append(aProgram)
}

self.programTableView.reloadData()
})
}

From there you can handle the tableView code; when a row needs refreshing, get that object from the dataSource via the index (row), read the data from that object and populate the tableView cell with it in whatever format you need.

Reload TableView data only after downloading everything from the firebase database Swift

You're nesting observers on nested data, which seems like a waste of code. When you attach an observer to a location, all data under that location is loaded already.

So you can just loop over the nested snapshot to get the same result:

newRef.observeSingleEvent(of: .value, with: { (snapshot) in
for child in snapshot.children {
let userSnapshot = child as! DataSnapshot
let userKey = userSnapshot.key

for child in userSnapshot.children {
let imageSnapshot = child as! DataSnapshot
var imageDownloaded: UIImage?
...

With that out of the way, let's move on to your real question: how can you detect when all images have loaded.

One simple, cross-platform way to do this is by simply counting how many images you have loaded, and compare that to how many images you know exist. Since you have a tree of only existing images, you can do both in a iteration over the double nested structure

let knownImageCount = 0 // we start with no knowledge of any image
let loadedImageCount = 0 // we also haven't loaded any image yet

for child in snapshot.children {
let userSnapshot = child as! DataSnapshot
let userKey = userSnapshot.key

knownImageCount = knownImageCount + userSnapshot.childrenCount // we've found out about N more images

for child in userSnapshot.children {
let imageSnapshot = child as! DataSnapshot
var imageDownloaded: UIImage?
...

URLSession.shared.dataTask(with: url!) { (data, response, error) in

...

loadedImageCount = loadedImageCount + 1 // we loaded an additional image

if loadedImageCount == knownImageCount {
... // we've loaded all known images, we're done!
}
}.resume()

Collection view not reloading after retrieving data

You should always update your UI elements on main thread. No exception here as well. Just execute the reload code on main thread.

dispatch_async(dispatch_get_main_queue(), {
self.mostPopularCollectionView.reloadData()
})

For Swift 3:

DispatchQueue.main.async { 
self.mostPopularCollectionView.reloadData()
}

How to reload data after all Firebase calls finished?

If you want to be notified when all the firebase calls have been completed you can use this code

let ref = FIRDatabase.database().reference()
ref.child("users/mchen/groups").observeSingleEvent(of: .value, with: { snapshot in
let groupKeys = snapshot.children.flatMap { $0 as? FIRDataSnapshot }.map { $0.key }

// This group will keep track of the number of blocks still pending
let group = DispatchGroup()

for groupKey in groupKeys {
group.enter()
ref.child("groups").child(groupKey).child("name").observeSingleEvent(of: .value, with: { snapshot in
print("Mary is a member of this group: \(snapshot.value)")
group.leave()
})
}

// We ask to be notified when every block left the group
group.notify(queue: .main) {
print("All callbacks are completed")
}
})

How does it work?

There are 4 main instructions involved.

  1. First of all we create a group DispatchGroup(). This value will keep track of the number of pending blocks.

    let group = DispatchGroup()
  2. Then before starting a new asynchronous call we tell the group there is a new pending block.

    group.enter()
  3. Inside the callback closure we tell the group that one block has finished its work.

    group.leave()
  4. We tell the block to run a closure when the number of blocks into the group does become zero.

    group.notify(queue: .main) {
    print("All callbacks are completed")
    }

Reload collection view data when user comes back to view controller

The view did load method is only called when the view is instantiated. It appears that it is not being triggered because your transitions are not deinstantiating the collection view cell. (you might be coming back from a pop over, for example)

To force the reload of the data you could try and put that same line of code under view will appear, which is triggered every time the view is about to be presented to the user.

Try doing:

override func viewWillAppear() {
super.viewWillAppear()
self.collectionView.reloadData()
}

The order normally goes, viewDidLoad, viewWillAppear and then viewDidAppear.

the above code should fix it. let me know if it doesn't.



Related Topics



Leave a reply



Submit