【问题标题】:Firebase Child Added Is Called Every time a Child is Changed每次更改子项时都会调用添加的 Firebase 子项
【发布时间】:2017-12-15 22:19:19
【问题描述】:

我有一个群消息应用程序,它可以正常工作,直到我想更改一些基本的群属性,例如群标题、图像等。在我展示我的代码以显示我的对话并更新它们之前,我将向你展示一些我的数据结构。

在处理对话的显示和编辑时,我使用两个主要节点。包含对话属性的整体对话节点和我当前用户中的对话节点。

这是我当前用户的对话节点的样子:

正如您在上图中所见,我的用户有一个带有对话 ID 列表的对话节点。这些对话 id 指的是我的数据库中的对话节点。这是对话节点的图片:

只是为了检查问题。基本上,当我更新任何对话属性(标题、图像、成员)时,它会调用我的 child added 方法,该方法会创建一个错误,我将在稍后显示。

这是我显示对话的代码:

func observeUserConversations() {
    guard let uid = currentUserProperties.id else {
        return
    }

    FIRDatabase.database().reference().child("users").child(uid).child("conversations").observe(.childAdded, with: { (snapshot) in
        FIRDatabase.database().reference().child("conversations").child(snapshot.key).observe(.value, with: { (conversationSnapshot) in
            if let conversation = Groups(snapshot: conversationSnapshot) {
                conversation.groupId = conversationSnapshot.key

                self.conversations.append(conversation)

                DispatchQueue.main.async(execute: {
                    self.tableView.reloadData()
                })
            }
        }, withCancel: nil)
    }, withCancel: nil)
}

这是我更新某些对话属性的代码:

static func updateConversationProperties(conversationId: String, property: String, propertyValue: String) {
    let updateConversationPropertyRef = FIRDatabase.database().reference().child("conversations").child(conversationId).child(property)
    updateConversationPropertyRef.setValue(propertyValue)
    ProgressHUD.showSuccess("Field Updated!")
}

请注意,我尝试使用更新子值而不是设置值,但仍然存在相同的错误。

总结一下,每当我更新对话属性时,都会调用子添加函数并将对话的重复版本附加到我的对话数组中。

我知道这可能有点令人困惑,所以我在这里有一段视频显示了这个错误: https://youtu.be/OhhnYzQRKi8

在上面的视频中,您会看到相同的对话被复制并添加了两次。

任何帮助将不胜感激!

更新

所以我稍微改变了我的观察者,看起来像这样:

    FIRDatabase.database().reference().child("users").child(uid).child("conversations").observe(.childAdded, with: { (snapshot) in
        FIRDatabase.database().reference().child("conversations").child(snapshot.key).observeSingleEvent(of: .value, with: { (conversationSnapshot) in
            if let conversation = Groups(snapshot: conversationSnapshot) {
                conversation.groupId = conversationSnapshot.key

                self.conversations.append(conversation)

                DispatchQueue.main.async(execute: {
                    self.tableView.reloadData()
                })
            }
        }, withCancel: nil)
    }, withCancel: nil)

在上面的代码中,一切正常,没有重复。但是,现在对话不会实时更新。相反,它们将显示旧数据并且不会更新到新更改的数据。此外,如果我添加对话,则不会显示新添加的对话。

【问题讨论】:

  • 您遇到的行为与您的代码中的行为有关。这是因为每次触发"conversations" 处的侦听器时,它都会在该快照键处创建一个新侦听器。我不确定第二个侦听器应该做什么,因为您可以从第一个侦听器获取快照值,但如果您需要获取一次值,请使用observeSingleEvent,如下所示:firebase.google.com/docs/database/ios/…
  • 好的,所以当我将其更改为observeSingleEvent 时,问题仍然存在,并且它也只检索一个对话而不是所有对话。第一个侦听器检索对话 ID,而第二个侦听器获取对话 ID 并观察另一个节点中的属性。请看我的帖子,看看我的数据结构。
  • 好的,所以我创建了两个类型为 observeSingleEvent 的侦听器,它消除了重复对话错误。但是,它增加了一个问题,即即使用户有多个对话,它也只检索一个对话。
  • 查看更新以了解更多上下文。
  • 感谢您为您的问题添加澄清信息!你说得对,我没有仔细阅读。我现在明白了,我已经添加了答案。

标签: ios arrays swift firebase firebase-realtime-database


【解决方案1】:

这是我注意到的:

按照您最初编写代码的方式,只要对 /"conversations"/snapshot.key 的值进行更改,就会触发第二个侦听器。每当进行此调用时,您都会将对话快照附加到对话数组:

FIRDatabase.database().reference().child("users").child(uid).child("conversations").observe(.childAdded, with: { (snapshot) in
    FIRDatabase.database().reference().child("conversations").child(snapshot.key).observe(of: .value, with: { (conversationSnapshot) in
        if let conversation = Groups(snapshot: conversationSnapshot) {
            conversation.groupId = conversationSnapshot.key

            self.conversations.append(conversation) // here is where you are appending the data. This will be appended each time a change is made

            DispatchQueue.main.async(execute: {
                self.tableView.reloadData()
            })
        }
    }, withCancel: nil)
}, withCancel: nil)

现在正如您所指出的,如果您将 FIRDatabase.database().reference().child("conversations").child(snapshot.key).observe 更改为 .observeSingleEvent,数据将不会再次附加,但您不会获得更新。一种选择是,只要触发了侦听器,就在数组中搜索快照键,然后在找到该索引处更新快照。可以肯定的是,这不是最有效的方法。

总而言之,听起来您确实需要使用observe,但就目前而言,数据是重复的,因为每当对快照的值进行更改时,代码都会将快照附加到数组的末尾。您将不得不使用self.conversations.append(conversation) 以外的其他内容。

如果您想直接给我发消息,我很乐意集思广益。

【讨论】:

  • 其实我只是想出了一个解决方案。我正要发布它。感谢你的帮助。我实际上确实使用了您所说的更新数组。
【解决方案2】:
    FIRDatabase.database().reference().child("users").child(uid).child("conversations").observe(.childAdded, with: { (snapshot) in
        FIRDatabase.database().reference().child("conversations").observe(.childAdded, with: { (conversationAdded) in
            if conversationAdded.key == snapshot.key {
                if let group = Groups(snapshot: conversationAdded) {
                    self.conversations.append(group)

                    DispatchQueue.main.async(execute: {
                        self.tableView.reloadData()
                    })
                }
            }
        })
    }, withCancel: nil)

    FIRDatabase.database().reference().child("users").child(uid).child("conversations").observe(.childAdded, with: { (snapshot) in
        FIRDatabase.database().reference().child("conversations").child(snapshot.key).observe(.childChanged, with: { (conversationSnapshot) in
            let conversationIdsArray = self.conversations.map({$0.groupId})

            let changeAtGroupIdIndex = conversationIdsArray.index(of: snapshot.key)

            let conversationToBeUpdated = self.conversations[changeAtGroupIdIndex!]

            conversationToBeUpdated.setValue(conversationSnapshot.value, forKeyPath: conversationSnapshot.key)
            self.tableView.reloadData()
        }, withCancel: nil)
    }, withCancel: nil)

在上面的代码中,我创建了两个不同的观察者。第一个在加载应用程序或添加对话时加载对话。如果孩子已经改变,第二个更新对话数组。这解决了这两个问题。

【讨论】:

    【解决方案3】:

    过滤数组,数据不包括刚刚接收到的对象。在我的例子中,通过一个唯一的 ID(如 groupID 或 chatID)识别现有数组中的该对象。然后重复的对象将被删除

    self.conversations = self.conversations.filter { obj in (obj.chatId as? String) != (data.chatId as? String) }
    
    self.conversations.append(data)
    

    【讨论】:

      猜你喜欢
      • 2017-07-13
      • 1970-01-01
      • 1970-01-01
      • 2017-09-14
      • 2016-10-27
      • 2015-08-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多