Firebase 查询移除带句柄的 Observer 时,不会调用其他观察者

When Firebase query removes Observer with handle, other observers are not called

我正在监视来自几个 UIViewControllers 的一些数据的状态。当 UIViewController deinit 发生时,我删除了带有句柄的特定观察者。现在我注意到,在从一个 UIViewController 中删除查询观察器之后,将来不会调用另一个 UIViewController 上的查询观察器,尽管数据在变化。请告诉我如何修复它?

  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 = self.userFriendshipEndObservers[observerID] else { return }
            query.removeObserver(withHandle: handle)
            self.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: UInt = 0

            handle = query.observe(.childRemoved, with: { (snap) in
                if snap.value is NSNull {
                    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)
            }
        }
    }

更新:我输出到日志,句柄,一切都正确添加和删除。例如 ProfileViewController 有 33 个 handle,ChatViewController 有 85 个 handle,在 ChatViewController deinit 后,删除 85 handle 的观察者,原来有 33 个 handle 的观察者,但它是未调用。

更新 1 如何知道:- 有多少观察者有 firebase 参考?

更新 2

class ProfileUserFormVC: FormViewController {

    // MARK: - Lifecycle

    override func viewDidLoad() {
        super.viewDidLoad()
        addObservers()
    }

    deinit {
        removeObservers()
        NotificationCenter.default.removeObserver(self)
    }

}

// MARK: - Obsevers

extension ProfileUserFormVC {

    private func addObservers() {
        guard let userID = self.userID else { return }
        MatchObserverManager.shared.observeNewMatchWithUser(self, isObserve: true, userID: userID, completion: { [weak self] (match) in
            // do something
        }) { (error) in

        }

        MatchObserverManager.shared.observeUserMatchDeleting(self, isObserve: true, userID: userID, completion: { [weak self] (removedMatch) in
            // do something
            }, fail: nil)

        FriendsObserver.shared.observeUserFriendshipEnd(self, isObserve: true, friendID: userID, endHandler: { [weak self] (removedFriend) in
            DispatchQueue.main.async {
                // do something with ui
            }
            }, fail: nil)
    }

    private func removeObservers() {
        guard let userID = user?.id else { return }
        MatchObserverManager.shared.observeNewMatchWithUser(self, isObserve: false, userID: userID, completion: nil, fail: nil)
        MatchObserverManager.shared.observeUserMatchDeleting(self, isObserve: false, userID: userID, completion: nil, fail: nil)
        FriendsObserver.shared.observeUserFriendshipEnd(self, isObserve: false, friendID: userID, endHandler: nil, fail: nil)
    }

}

经理

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 userFriendshipEndObservers = [String : UInt]()

    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 = self.userFriendshipEndObservers[observerID] else { return }
            query.removeObserver(withHandle: handle)
            self.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: UInt = 0

            handle = query.observe(.childRemoved, with: { (snap) in
                if snap.value is NSNull {
                    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)
            }
        }
    }

}

更新3我做了一个快速的改变,虽然这样做是不对的,但是我在接收到handler之后返回了handle,然后我赋值了一个变量给ViewController,在 deinit 期间我也删除了观察者。我得到了相同的结果。也就是说,如果我删除一个带句柄的观察者,则第二个观察者将不起作用。在此之前,我的代码以其原始形式运行。

open func observeUserFriendshipEnd(_ observer: FirebaseObserverDelegate, isObserve: Bool, friendID: String, handle: UInt?, handleHandler: ((_ handle: UInt) -> Void)?, 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 = handle else { return }
        query.removeObserver(withHandle: _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: UInt = 0

        handle = query.observe(.childRemoved, with: { (snap) in
            if snap.value is NSNull {
                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)
        })

        handleHandler?(handle)
        self.queue.sync {
            self.userFriendshipEndObservers[observerID] = handle
            self.addObserver(observerID, handle: handle, query: query, ref: nil)
        }
    }
}

这是我的代码错误,我更改了 FriendsObserver,现在一切正常。

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)
            }
        }
    }

}