With Firebase, Swift removeObserver(withHandle does not remove the observer
If you have the following code:
var postsRef: FIRDatabaseReference!
var postRefHandle: FIRDatabaseHandle!
var query = FIRDatabaseQuery()
func addHandler() {
self.postsRef = self.ref.child("posts")
var count = 20
self.query = self.postsRef.queryOrdered(byChild: "sortTimestamp")
self.postRefHandle = self.query.queryLimited(toFirst: UInt(count)).observe(.childAdded, with: { snapshot in
print(snapshot)
})
}
and at a later time you do this function
self.postsRef.removeObserver(withHandle: self.postRefHandle!)
It removes the observer. This is tested code.
To the second part of your question: querySingleEvent and observe do the same thing data wise but have different behaviors. They will both always get current data - modified by startAt, endAt, equalTo etc.
observeSingleEvent returns the data, does NOT leave an observer so you
will not be notified if that data changesobserve returns the data and leaves an observer attached to the node
and will notify you of future changes.
.childAdded: when any children are added to the node
.childChanges: when any children change in the node
.childRemoved: when a child is removed.
Firebase RemoveObserver methods does not remove observer
Currently I think your ref
is not being made right since you are calling this function in your custom method. You should call it in viewDidDisappear
method of your viewcontroller
According to the Firebase site
You should remove listeners or observers in
viewDidDisappear
methodIf your controller is still syncing data when the view has
disappeared, you are wasting bandwidth and memory
Learn more here https://firebase.googleblog.com/2015/10/best-practices-for-ios-uiviewcontroller_6.html
Remove Firebase observers with a FirebaseHandle does not work
You need to call removeObserver(withHandle: ...)
on the same reference that you registered it on.
So:
rootRef.child("userMessages").child(uid).child(toId).removeObserver(withHandle: handleUserMessagesAdded)
iOS Firebase RTDB observer - remove observer for the path which is NOT existing any longer
The observer will stay active after the node is deleted, as somebody may later recreate the node.
If you want to remove the observer, you'll have to do so from your code by keeping a handle to the observer when you attach it. For more on this see the Firebase documentation on detaching listeners or the code in this answer: Firebase 'Observe' called multiple times with Swift on iOS
Firebase : How to removeObserver(withHandle:) after observeSingleEvent()?
Since databaseReference.observeSingleEvent(...)
doesn't return a handle that you can remove the only option is to use databaseReference.observe(...)
.
Just remove the handle manually once you need to OR when the first event fires.
Update
Try using this extension:
public extension FIRDatabaseReference {
@discardableResult
public func observeOneEvent(of eventType: FIRDataEventType, with block: @escaping (FIRDataSnapshot) -> Swift.Void) -> FIRDatabaseHandle {
var handle: FIRDatabaseHandle!
handle = observe(eventType) { (snapshot: FIRDataSnapshot) in
self.removeObserver(withHandle: handle)
block(snapshot)
}
return handle
}
}
When Firebase query removes Observer with handle, other observers are not called
It was my mistake in the code, I changed FriendsObserver and now everything works.
class FriendsObserver: FirebaseObserver {
static let shared = FriendsObserver()
private override init() {
super.init()
}
// MARK: - Queues
private let queue = DispatchQueue(label: "com.myapp.FriendsObserver.queue")
// MARK: - Data
private var userFriendshipStartObservers = [String : DatabaseHandle]()
private var userFriendshipEndObservers = [String : DatabaseHandle]()
open func observeSpecificUserFriendshipStart(_ observer: FirebaseObserverDelegate, isObserve: Bool, userID: String, startHandler: ((_ friend: FriendModel) -> Void)?, fail: ((_ error: Error) -> Void)?) {
let observerID = observer.observerID
let realmManager = RealmManager()
let timestamp = Date().currentTimestamp
guard let currentUserID = realmManager.getCurrentUser()?.id else { return }
let query = Database.database().reference().child(FriendsPaths.MainGateways.friends.description).child(currentUserID).child(FriendsPaths.SubGateways.userFriends.description).queryOrdered(byChild: "friendID").queryEqual(toValue: userID)
if !isObserve {
guard let handle = userFriendshipStartObservers[observerID] else { return }
query.removeObserver(withHandle: handle)
userFriendshipStartObservers[observerID] = nil
// system
removeObserverModel(observerID, handle: handle)
return
}
DispatchQueue.global(qos: .background).async {
var isContinue = true
self.queue.sync {
if self.userFriendshipStartObservers[observerID] != nil {
isContinue = false
}
}
guard isContinue else { return }
var handle: DatabaseHandle = 0
handle = query.observe(.childAdded, with: { (snapshot) in
guard snapshot.exists() else { return }
guard let dict = snapshot.value as? [String : Any] else { return }
guard let friendModel = Mapper<FriendModel>().map(JSON: dict) else { return }
guard timestamp < friendModel.friendshipTimeStamp else { return }
if friendModel.friendID == userID {
startHandler?(friendModel)
}
}, withCancel: { (error) in
fail?(error)
})
self.queue.sync {
self.userFriendshipStartObservers[observerID] = handle
self.addObserver(observerID, handle: handle, query: query, ref: nil)
}
}
}
/// Only one observer on one object
open func observeUserFriendshipEnd(_ observer: FirebaseObserverDelegate, isObserve: Bool, friendID: String, endHandler: ((_ removedFriendModel: FriendModel) -> Void)?, fail: ((_ error: Error) -> Void)?) {
let observerID = observer.observerID
let realmManager = RealmManager()
guard let currentUserID = realmManager.getCurrentUser()?.id else { return }
let query = Database.database().reference().child(FriendsPaths.MainGateways.friends.description).child(currentUserID).child(FriendsPaths.SubGateways.userFriends.description).queryOrdered(byChild: "friendID").queryEqual(toValue: friendID)
if !isObserve {
guard let handle = userFriendshipEndObservers[observerID] else { return }
query.removeObserver(withHandle: handle)
userFriendshipEndObservers[observerID] = nil
// system
removeObserverModel(observerID, handle: handle)
return
}
DispatchQueue.global(qos: .background).async {
var isContinue = true
self.queue.sync {
if self.userFriendshipEndObservers[observerID] != nil {
isContinue = false
}
}
guard isContinue else { return }
var handle: DatabaseHandle = 0
handle = query.observe(.childRemoved, with: { (snap) in
guard snap.exists() else { return }
guard let dict = snap.value as? [String : Any] else { return }
guard let removedFriendModel = Mapper<FriendModel>().map(JSON: dict) else { return }
let friendRealmManager = FriendRealmManager()
friendRealmManager.removeFriend(removedFriendModel.friendID)
if removedFriendModel.friendID == friendID {
endHandler?(removedFriendModel)
}
}, withCancel: { (error) in
fail?(error)
})
self.queue.sync {
self.userFriendshipEndObservers[observerID] = handle
self.addObserver(observerID, handle: handle, query: query, ref: nil)
}
}
}
}
How to remove firebase observer?
You need
let current = ref.child("doctors").child(userID!)
current.observe ///
current.removeAllObservers()
if you need to removeObservers you need to go deep as you add childs , as removeAllObservers
for parents doesn't remove them for childs
FirebaseQuery Observer not Removing
You need to remove the observer on the exact query object that you registered it on.
So:
self.query.removeObserver(withHandle: postRefHandle)
or
self.query.removeAllObservers()
Related Topics
Detailed Instruction on Use of Nsopenpanel
Rxswift/Rxcocoa: Prevent Uitextfield from Having More Than ... Characters
Timedmetadata' Deprecated. Another Method? <Updated>
Datepicker Using Time-Interval in Swiftui
How to Make Firebase Database Data the Data Source for Uicollection View
How to Open Another Window in MACos in Swift with Cocoa
Reusing Security Scoped Bookmark
Swift String VS. String! VS. String
Nsfetchedresultscontollerdelegate For Collectionview
How to Use Unsafemutablerawpointer to Fill an Array
What Is the "@Exported" Attribute in Swift
Calculate Area of Mkpolygon in an Mkmapview
Nstextalignment.Justified for Uilabel Does Not Work
Drawing a 3D Arc and Helix in Scenekit