swift - 同一应用程序中的两个观察者相互干扰

标签 swift firebase firebase-realtime-database

我的应用程序中有两个观察者,一个是有序的,另一个不是。无序观察者似乎会干扰有序观察者的结果。

我的数据库如下所示:

"events" : {
    "Oo75nbcDsUK7vPWGDbnL" : {
      "queue" : {
          "K7THdbKzd2aSfaD9a0xmsszkReq1" : {
            "queuePosition" : 1
          },
          "R5UwSxlH3vhH6SjTNMGfMoiaGae2" : {
            "queuePosition" : 2
          }
       }
    }
}

我有一个类,它使用以下静态函数处理实时数据库的观察者创建:

static func listenToRtdbDocument<T: JSONDecodable>(_ refString: String, eventType: DataEventType = .value, orderedByChild: String? = nil, limit: Int? = nil, fromCollection collection: Firebase.RtdbCollections? = nil, completion: @escaping (_ decodedDoc: T?, _ error: Error?) -> ()) -> DatabaseHandle {
    var query: DatabaseQuery
    if let orderedByChild = orderedByChild {
        query = rtdb.child(refString).queryOrdered(byChild: orderedByChild)
    } else {
        query = rtdb.child(refString)
    }

    if let limit = limit {
        query.queryLimited(toFirst: UInt(limit))
    }

    return query.observe(eventType, with: { snapshot in
        guard var docData = snapshot.value as? [String : Any] else {
            completion(nil, nil)
            return
        }
        docData["id"] = snapshot.key
        let decodedDoc = T(json: docData)
        completion(decodedDoc, nil)
    }) { error in
        completion(nil, error)
    }
}

这将创建观察者,然后返回一个DatabaseHandle引用。我在应用程序的两个不同位置使用此函数。第一个是在 Collection View 单元模型内。这会像这样调用该函数:

queuerRefString = "events/Oo75nbcDsUK7vPWGDbnL/queue/R5UwSxlH3vhH6SjTNMGfMoiaGae2"

func listenToQueuer(updateHandler: @escaping (QueuerJSONModel?) -> ()) {
    guard queuerListener == nil,
        let refString = queuerRefString else { return }

    queuerListener = FirebaseClient.listenToRtdbDocument(refString) { (queuer: QueuerJSONModel?, error) in
        guard error == nil else {
            return
        }
        updateHandler(queuer)
    }
}

第二个来自 View Controller 模型。该 View Controller 显示在 Collection View 单元格上:

queueRefString = "events/Oo75nbcDsUK7vPWGDbnL/queue"


func listenToQueue() {
    guard queueChildAddedListener == nil
        let refString = queueRefString else { return }

    queueChildAddedListener = FirebaseClient.listenToRtdbDocument(refString, eventType: .childAdded, orderedByChild: "queuePosition", limit: 25) { [weak self] (queuer: QueuerJSONModel?, error) in
        guard let strongSelf = self,
            let queuer = queuer,
            error == nil else {
                print("an error occurred")
            return
        }
        strongSelf.queuers?.append(queuer)
    }
}

对于有序数组观察者,这始终首先返回当前用户,然后返回有序队列的其余部分。例如。如果当前用户位于位置 5,则 queuers 数组将如下所示:

5, 1, 2, 3, 4, 6, 7, 8, 9, 10

如何阻止它们互相干扰?

更新

如何重现:

将此代码放入一个 View Controller 的 viewDidLoad 方法中:

let test1 = Database.database().reference()
        .child("events/Oo75nbcDsUK7vPWGDbnL/queue/R5UwSxlH3vhH6SjTNMGfMoiaGae2")
        .observe(.value, with: { snapshot in
            guard var docData = snapshot.value as? [String : Any] else {
                return
            }
            docData["id"] = snapshot.key
            let queuer = QueuerJSONModel(json: docData)!
            print("ok we got", queuer.queuePosition) // Prints out 2
        })

然后将此代码放入另一个 View Controller 的 viewDidLoad 方法中:

let test2 = Database.database().reference()
        .child("events/Oo75nbcDsUK7vPWGDbnL/queue")
        .queryOrdered(byChild: "queuePosition")
        .queryLimited(toFirst: 25)
        .observe(.childAdded, with: { snapshot in
            guard var docData = snapshot.value as? [String : Any] else {
                return
            }
            docData["id"] = snapshot.key
            let queuer = QueuerJSONModel(json: docData)!
            print("ok we got", queuer.queuePosition) // Prints out 2, then 1
        })

首先查看包含 test1 的 View Controller ,然后查看包含 test2 的 View Controller 。我使用标签栏 Controller 在两者之​​间切换。

奇怪的是,如果将这两段代码放在 View Controller 的同一个 viewDidLoad 方法中,则有序监听器将按预期工作。

最佳答案

您观察到的行为是由于“value”事件与“childAdded”事件不同的方式造成的。

在您的第一个观察者(使用 .value)中,您只需在单个快照中请求来自 events/Oo75nbcDsUK7vPWGDbnL/queue/R5UwSxlH3vhH6SjTNMGfMoiaGae2 的所有数据。如果在仍添加该观察者的情况下该位置下的任何数据发生变化,您的观察者将再次被调用,并获得该位置所有内容的快照。

在第二个观察者(使用 .childAdded)中,您请求为 events/Oo75nbcDsUK7vPWGDbnL/queue 中的每个子项调用一次观察者。如果您有两个 child ,您的观察员将会为每个 child 调用一次。当新的子节点添加到该位置时,您的观察者将再次被调用,每个新的子节点调用一次。

观察者不会互相干扰。他们只是做不同的事情。

关于swift - 同一应用程序中的两个观察者相互干扰,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51159730/

相关文章:

android - IONIC apk 生成问题

java - 如果我想使用 Google App Engine 从服务器代码写入 Firebase,是否需要启用计费?

Swift 数据库检索数据

ios - Swift 链接器错误 : Undefined symbol for surely available API presentationDimensions

ios - 如何在 UITextView 的文本后面动态创建多个按钮

javascript - 为什么 Firebase 无法识别登录用户?

Swift 可编码多种类型

authentication - firebase unauth 与 google 不允许更改用户

ios - 添加 child 时,如何使用 Swift 和 Firebase 向每台设备发送通知?

javascript - Firebase Web 检索更具体的数据并对其进行排序