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

Swift 同一应用程序中的两个观察者相互干扰,swift,firebase,firebase-realtime-database,Swift,Firebase,Firebase Realtime Database,我的应用程序中有两个观察者,一个是订购的,一个不是。无序观察者似乎会干扰有序观察者的结果 我的数据库如下所示: "events" : { "Oo75nbcDsUK7vPWGDbnL" : { "queue" : { "K7THdbKzd2aSfaD9a0xmsszkReq1" : { "queuePosition" : 1 }, "R5UwSxlH3vhH6SjTNMGfMoiaGae2" :

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

我的数据库如下所示:

"events" : {
    "Oo75nbcDsUK7vPWGDbnL" : {
      "queue" : {
          "K7THdbKzd2aSfaD9a0xmsszkReq1" : {
            "queuePosition" : 1
          },
          "R5UwSxlH3vhH6SjTNMGfMoiaGae2" : {
            "queuePosition" : 2
          }
       }
    }
}
5, 1, 2, 3, 4, 6, 7, 8, 9, 10
我有一个类,通过以下静态函数处理实时数据库的观察者创建:

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)
    }
}
第二个是来自视图控制器模型。此视图控制器通过集合视图单元格显示:

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
数组将如下所示:

"events" : {
    "Oo75nbcDsUK7vPWGDbnL" : {
      "queue" : {
          "K7THdbKzd2aSfaD9a0xmsszkReq1" : {
            "queuePosition" : 1
          },
          "R5UwSxlH3vhH6SjTNMGfMoiaGae2" : {
            "queuePosition" : 2
          }
       }
    }
}
5, 1, 2, 3, 4, 6, 7, 8, 9, 10
我怎样才能阻止他们互相干扰

更新

如何复制:

将此代码放在一个视图控制器的
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
        })
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
        })
然后将此代码放入另一个视图控制器的
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
        })
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
的视图控制器,然后查看中有
test2
的视图控制器。我使用选项卡栏控制器在两者之间切换


奇怪的是,如果这两段代码放在视图控制器的同一个
viewdiload
方法中,那么有序的侦听器会按预期工作。

您观察到的行为是因为“value”事件与“childAdded”事件不同

在第一个观察者(使用
.value
)中,您只需在单个快照中从
事件/Oo75nbcDsUK7vPWGDbnL/queue/r5uwsxlh3vh6sjtnmgfmoiagae2
请求所有数据。如果该位置下的任何数据在仍然添加该观察者的情况下发生更改,您的观察者将再次被调用,并提供该位置上所有内容的快照

在第二个观察者中(使用
.childAdded
),您请求在
事件/Oo75nbcDsUK7vPWGDbnL/queue
中为每个孩子调用一次观察者。如果您在那里有两个孩子,您的观察者将为每个孩子调用一次。当在该位置添加新的子对象时,您的观察者将再次被调用,每次调用一次


观察员之间没有相互干扰。他们只是在做不同的事情。

这是Firebase支持部门对我的问题的回答:

显然,这是一种有意的行为。childAdded的想法是,以下是您迄今为止检索到的内容,以及尚未添加的内容。因此,添加的childAdded将R5UwSxlH3vhH6SjTNMGfMoiaGae2作为预加载的数据,并将K7THDBKZD2ASFAD9A0XMSZKREQ1作为新数据返回


这样,即使您请求订购,如果您在设备上预加载了数据,也不一定会重新订购

观察者之间不会相互干扰。每一个都完全独立地运行。@DougStevenson这正是我所希望的,但当我注释掉我在代码中声明的第二个观察者时,第一个观察者会以正确的顺序返回对象。顺便说一句,这些都用在我的应用程序的不同部分,所以不要写入同一个数组或任何东西。什么代码决定了你显示的输出?您正在打印myArray的内容吗?请编辑问题以显示所有涉及的代码。@DougStevenson Hi,已经用更多代码更新了我的问题。很难看到您在这里做的所有事情(我认为仍然缺少代码)。但是这两个查询是否可能同时运行,但都以不确定的方式更新某些共享数据结构?这是正确的,但不能解释为什么没有按照我指定的顺序调用
.childAdded
观察者?我确实想对
事件/Oo75nbcDsUK7vPWGDbnL/queue/r5uwsxlh3vh6sjtnmgfmoiagae2使用
.value
,我确实想对
事件/Oo75nbcDsUK7vPWGDbnL/queue
使用
.childAdded
,原因也是您在文档中指定的。您尝试重现我的问题了吗?我的临时解决方案是在我想要观察
.childAdded
时删除
.value
观察者,然后它会产生我想要的结果。不过,这确实让人感觉像是黑客攻击。访问两者之间的共享数据肯定是做错了什么。它们只是不相互干扰。如果他们这样做了,那么将会有很多有缺陷的应用程序。实际上,应用程序应用了几十个或更多的同步侦听器,每个侦听器都能按预期工作。我绝对不是。我已经创建了一个新项目,并设法按照我所描述的方式重现我的问题。有没有什么地方可以让我把这封信寄给你们看?不过,您必须创建自己的数据库,以使用自己的登录详细信息模拟我的数据库。