With Firebase, Swift Removeobserver(Withhandle Does Not Remove the Observer

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 changes

observe 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 method

If 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



Leave a reply



Submit