我的应用程序中有两个观察者,一个是有序的,一个不是。无序观察者似乎会干扰有序观察者的结果。
我的数据库如下:
"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
引用。我在应用程序的两个不同位置使用了此功能。第一个是在集合视图单元格模型内部。这样调用该函数:
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)
}
}
第二个是来自视图控制器模型的。该视图控制器通过集合视图单元格呈现:
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
如何阻止它们相互干扰?
更新
如何复制:
将此代码放在一个视图控制器的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
})
然后将这段代码放在另一个视图控制器的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
的视图控制器,然后查看具有test2
的视图控制器。我使用标签栏控制器在两者之间进行切换。
奇怪的是,如果将这两段代码放在视图控制器的同一viewDidLoad
方法中,那么有序侦听器将按预期工作。
答案 0 :(得分:0)
您观察到的行为是由于“值”事件与“ childAdded”事件不同的原因。
在您的第一个观察者中(使用.value
),您只是在单个快照中从events/Oo75nbcDsUK7vPWGDbnL/queue/R5UwSxlH3vhH6SjTNMGfMoiaGae2
请求所有数据。如果在仍添加该观察者的情况下该位置下的任何数据发生更改,您的观察者将再次被调用,并获取该位置所有内容的快照。
在您的第二个观察者中(使用.childAdded
),您要求在events/Oo75nbcDsUK7vPWGDbnL/queue
处为每个孩子调用一次观察者。如果您有两个孩子,则每个孩子都会被召唤一次您的观察员。在该位置添加了新的孩子之后,您的旁听者将再次被召唤,每次给新孩子打电话一次。
观察者不会互相干扰。他们只是在做不同的事情。
答案 1 :(得分:0)
这是Firebase支持人员对我的问题的答复:
显然,这是预期的行为。 childAdded的想法是,这是您到目前为止检索到的内容,尚未添加。因此,childAdded将R5UwSxlH3vhH6SjTNMGfMoiaGae2作为您的预加载数据,并返回K7THdbKzd2aSfaD9a0xmsszkReq1作为您的新数据。
通过这种方式,即使您已请求订购,但如果您已在设备上预加载了数据,也不一定会重新订购。