Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase removing observers

I have a problem removing a Firebase observer in my code. Here's a breakdown of the structure:

var ref = Firebase(url:"https://MY-APP.firebaseio.com/")
var handle = UInt?

override func viewDidLoad() {
    handle = ref.observeEventType(.ChildChanged, withBlock: {
        snapshot in

        //Do something with the data
    }
}

override func viewWillDisappear(animated: Bool) {
    if handle != nil {
        println("Removed the handle")
        ref.removeObserverWithHandle(handle!)
    }
}

Now when I leave the viewcontroller, I see that "Removed the handle" is printed, but when I return to the viewcontroller, my observer is called twice for each event. When I leave and return again, it's called three times. Etc. Why is the observer not being removed?

I do also call ref.setValue("some value") later in the code, could this have anything to do with it?

like image 741
Nicolaas Wagenaar Avatar asked Nov 25 '14 10:11

Nicolaas Wagenaar


People also ask

How do I get rid of Firebase listener?

Detach listeners Callbacks are removed by calling the off() method on your Firebase database reference. You can remove a single listener by passing it as a parameter to off() . Calling off() on the location with no arguments removes all listeners at that location.

How do I remove a value from Firebase?

The simplest way for deleting data is to call removeValue() on a reference to the location of that data. We can also delete data by specifying null as the value for another write operation such as setValue() or updateChildren().

What does onSnapshot do?

You can listen to a document with the onSnapshot() method. An initial call using the callback you provide creates a document snapshot immediately with the current contents of the single document. Then, each time the contents change, another call updates the document snapshot.


2 Answers

Thought I was having this bug but in reality I was trying to remove observers on the wrong reference.

ORIGINAL CODE:

let ref: FIRDatabaseReference = FIRDatabase.database().reference()
var childAddedHandles: [String:FIRDatabaseHandle] = [:]

func observeFeedbackForUser(userId: String) {
    if childAddedHandles[userId] == nil { // Check if observer already exists

        // NOTE: - Error is caused because I add .child(userId) to my reference and
        //     do not when I call to remove the observer.

        childAddedHandles[userId] = ref.child(userId).observeEventType(.ChildAdded) { 
            [weak self] (snapshot: FIRDataSnapshot) in

            if let post = snapshot.value as? [String:AnyObject],
               let likes = post["likes"] as? Int where likes > 0 {             

                self?.receivedFeedback(snapshot.key, forUserId: userId)          
            }
        }
    }
}

func stopObservingUser(userId: String) {
    // THIS DOES NOT WORK

    guard let cah = childAddedHandles.removeValueForKey(userId) else {
        print("Not observing user")
        return
    }

    // Error! I did not add .child(userId) to my reference
    ref.removeObserverWithHandle(cah)
}

FIXED CODE:

func stopObservingUser(userId: String) {
    // THIS WORKS

    guard let cah = childAddedHandles.removeValueForKey(userId) else {
        print("Not observing user")
        return
    }

    // Add .child(userId) here
    ref.child(userId).removeObserverWithHandle(cah)
}
like image 184
Reid Avatar answered Oct 02 '22 19:10

Reid


Given it's April 2015 and the bug is still around I'd propose a workaround for the issue:

  • keep a reference of the handles (let's say in a dictionary and before initiating a new observer for the same event type check if the observer is already there.

Having the handles around has very low footprint (based on some official comments :) ) so it will not hurt that much.

like image 41
Daniel K Avatar answered Oct 02 '22 18:10

Daniel K