Reputation: 170
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?
Upvotes: 8
Views: 4443
Reputation: 2366
Observers must be removed on the same reference path they were put upon. And for the same number of times they were issued, or use ref.removeAllObservers() for each path.
Here's a trick I use, to keep it tidy:
var fbObserverRefs = [FIRDatabaseReference]() // keep track of where observers defined.
...then, put observers in viewDidLoad():
fbObserverRefs.append(ref.child("user/\(uid)"))
fbObserverRefs.last!.observe(.value, with: { snap in
// do the work...
})
...then, in viewWillDisappear(), take care of removing any issued observers:
// Only true when popped from the Nav Controller stack, ignoring pushes of
// controllers on top.
if isBeingDismissed || isMovingFromParentViewController {
fbObserverRefs.forEach({ $0.removeAllObservers() })
}
Upvotes: 0
Reputation: 734
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)
}
Upvotes: 2
Reputation: 53
Given it's April 2015 and the bug is still around I'd propose a workaround for the issue:
Having the handles around has very low footprint (based on some official comments :) ) so it will not hurt that much.
Upvotes: 1