Archie Gertsman
Archie Gertsman

Reputation: 1661

Swift Firebase observe with .childAdded retrieving duplicate data

I have a UICollectionViewController which acts as a feed that retrieves and displays data from my Firebase database. It's the window's root view controller, so it always exists. My issue is that every time the controller appears, all of the children from its observed node get added to the collection view. This is fine initially, but when I leave the controller and return, all of the same data gets appended, creating duplicates. Here is some pseudo-code, representing my interaction with Firebase:

class ViewController: UIViewController {

    var children_query: DatabaseQuery!

    override func viewDidLoad() {
        super.viewDidLoad()
        self.children_query = Database.database().reference().child("children").queryOrdered(byChild: "timestamp").queryStarting(atValue: Date().timeIntervalSince1970)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.observeAddedChildren()
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        self.children_query.removeAllObservers()
    }

    func observeAddedChildren() {
        self.children_query.observe(.childAdded, with: { snapshot in
            print(snapshot.value)
        })
    }

}

In this pseudo-code, instead of dealing with UI, I simply print snapshot, but the point remains. All of the children get printed each time the controller appears. How can I retrieve only data that hasn't been retrieved? Thanks.

Upvotes: 0

Views: 1145

Answers (1)

anon
anon

Reputation:

I haven't used Firebase, but when you pass a block to the observe function, there's nothing to suggest the observation stops when the view disappears.

So I wonder if calling observe multiple times is the problem. Have you tried calling observe just once, in ViewDidLoad?

Alternatively, have a property to record whether the observation has been started:

var observing: Bool = false

func observeAddedChildren() {
    if observing {
        return false
    }

    self.children_query.observe(.childAdded, with: { snapshot in
        print(snapshot.value)
    })
    observing = true
}

Edit: here's a couple more ways, because you're presumably adding the snapshot items to an array or other collection, then your UICollectionViewDataSource is reading stuff from that array.

So either:

  1. empty this array inside viewWillAppear and then call self.collectionView.reloadData(), or
  2. if your snapshot object has a unique identifier property, then put this into an array, and then the observe block can ignore items it's already seen before

Like this:

var snapshotIDs : [String] = Array<String>()

func observeAddedChildren() {
    self.children_query.observe(.childAdded, with: { snapshot in
        if !snapshotIDs.contains(snapshot.uniqueID) {
            print(snapshot.value)
            snapshotIDs.append(snapshot.uniqueID)
        }
    })
}

Upvotes: 1

Related Questions