【问题标题】:Firebase & Swift: Update user information in realtime on app after it updates on firebaseFirebase 和 Swift:在 Firebase 上更新后,在应用上实时更新用户信息
【发布时间】:2019-07-27 04:30:16
【问题描述】:

我的应用要求您至少关注四个人(或者按钮显示“关注至少 4 个朋友”)才能开始回答关于您关注的人的多项选择式问答。现在,每当用户关注某人时,它都会在 firebase 上更新,但他们关注的人不会实时显示在 MCQ/Q&A 页面上,除非我从一开始就运行该应用程序。

如何让它实时更新,而不必从头开始重新运行?

更新:

我已将之前的 observeSingleEvent 函数更改为使用 DataEventType.value 的观察函数,它比以前更好,因为它会在我关注和取消关注人时更新,但前提是用户有超过 4 个关注者。

现在,如果我取消关注 4 个以下的人,它会显示“正确关注至少 4 个朋友”,但当我关注 4 个或更多时,按钮会调用 4 个随机用户,但会冻结且无法按下。

此外,当我尝试在两个观察功能的底部添加解除功能时 - 它会出错并且不会让我进入页面

这是更新后的代码(我希望我解释正确,如果这看起来像一个愚蠢的问题,我很抱歉我感谢任何帮助/解释) - 提前致谢 :)

viewDidLoad 中调用的函数是:

var ref: DatabaseReference = Database.database().reference()
var currNames: [String] = []
var currIds: [String] = []
let imageViewA = UIImageView()
let imageViewB = UIImageView()
let imageViewC = UIImageView()
let imageViewD = UIImageView()

func getFourRandomNodesAndPrintUserName() {
    self.currNames = []
    self.currIds = []

    var myKeyArray = [String]()
    guard let uid = Auth.auth().currentUser?.uid else {
        return
    }

    let ref = self.ref.child("following").child(uid) //retreives all nodes in the following node
    ref.observe(DataEventType.value, with: { (snapshot) in
        print(snapshot.children.allObjects)
        for child in snapshot.children { //build the array of keys
            let snap = child as! DataSnapshot
            let key = snap.key
            myKeyArray.append(key)
    }

        var randomKeyArray = [String]()
        let numFollowers = min(4, myKeyArray.count)
        for _ in 0..<numFollowers { //will iterate four times
            let count = myKeyArray.count //get the number of elements
            let randomInt = Int.random(in: 0..<count) //get a random index for the array
            let randomUserKey = myKeyArray[randomInt]
            randomKeyArray.append(randomUserKey)
            myKeyArray.remove(at: randomInt) //remove that object so it's not selected again
        }

        let numberOfKeys = randomKeyArray.count
        var namesRemaining = numberOfKeys
        var names = [String]()
        var namesWithUrl = [String : String]()
        var profileImages = [String]()

        for i in 0..<numberOfKeys {
            let thisUserKey = randomKeyArray[i]
            let userRef = self.ref.child("users").child(thisUserKey)
            userRef.observeSingleEvent(of: .value, with: { snapshot in
                let name = snapshot.childSnapshot(forPath: "fullname").value as! String
                let profileImageUrl = snapshot.childSnapshot(forPath: "profileImageUrl").value as! String
                print(name)
                print(profileImageUrl)
                namesRemaining -= 1
                names.append(name)
                profileImages.append(profileImageUrl)
                namesWithUrl[name] = profileImageUrl

                self.currIds.append(thisUserKey)

                if numFollowers <= 3 {
                    self.optionA.setTitle("Follow\nat least\n4 friends!", for: .normal)
                    self.optionA.isEnabled = false

                    self.optionB.setTitle("Follow\nat least\n4 friends!", for: .normal)
                    self.optionB.isEnabled = false

                    self.optionC.setTitle("Follow\nat least\n4 friends!", for: .normal)
                    self.optionC.isEnabled = false

                    self.optionD.setTitle("Follow\nat least\n4 friends!", for: .normal)
                    self.optionD.isEnabled = false
                }
                else if namesRemaining == 0 {
                    self.currNames = names
                    self.optionA.setTitle(names[0], for: .normal)
                    let optionAUrl = URL.init(string: namesWithUrl[names[0]]!)
                    self.imageViewA.sd_setImage(with: optionAUrl)

                    self.optionB.setTitle(names[1], for: .normal)
                    let optionBUrl = URL.init(string: namesWithUrl[names[1]]!)
                    self.imageViewB.sd_setImage(with: optionBUrl)

                    self.optionC.setTitle(names[2], for: .normal)
                    let optionCUrl = URL.init(string: namesWithUrl[names[2]]!)
                    self.imageViewC.sd_setImage(with: optionCUrl)

                    self.optionD.setTitle(names[3], for: .normal)
                    let optionDUrl = URL.init(string: namesWithUrl[names[3]]!)
                    self.imageViewD.sd_setImage(with: optionDUrl)
                }
                //self.dismiss(animated: true, completion: nil) //it works when i don't include this otherwise there is a bug

            })
        }
        //self.dismiss(animated: true, completion: nil) //it works when i don't include this otherwise there is a bug out
    })
}

更新:

我从 firebase 复制了我的 Realtime DB JSON 结构的 sn-p:

"following" : {
      "MJxCFUX0jpXJD1a2u0iqt6xSAdB3" : {
      "5W6Qf4cJKQb5nY1PthMUelHLShy2" : true,
      "GU03rUQPrIX4zleX1S8L8anSWmn2" : true,
      "MfeIehKJKzS2Cf0kA0JTmHZGWSu1" : true
    },
      "MfeIehKJKzS2Cf0kA0JTmHZGWSu1" : {
      "5W6Qf4cJKQb5nY1PthMUelHLShy2" : true,
      "GU03rUQPrIX4zleX1S8L8anSWmn2" : true,
      "MJxCFUX0jpXJD1a2u0iqt6xSAdB3" : true,
      "nZLf70wvZUYqrAExXmnSX9G7Rar2" : true
    },
      "nZLf70wvZUYqrAExXmnSX9G7Rar2" : {
      "5W6Qf4cJKQb5nY1PthMUelHLShy2" : true,
      "FwUzqbn49FP5jS5mIuaAEnrxvpj2" : true,
      "GU03rUQPrIX4zleX1S8L8anSWmn2" : true,
      "MJxCFUX0jpXJD1a2u0iqt6xSAdB3" : true,
      "MfeIehKJKzS2Cf0kA0JTmHZGWSu1" : true
    }


"users" : {
     "5W6Qf4cJKQb5nY1PthMUelHLShy2" : {
      "email" : "aaaa@gmail.com",
      "fullname" : "Aaaa",
      "fullname_lowercase" : "aaaa",
      "profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/pinion-4896b.appspot.com/o/profile_image%2F5W6Qf4cJKQb5nY1PthMUelHLShy2?alt=media&token=eba41189-98dc-45d0-bccc-769cc8fa872f"
    },
     "FwUzqbn49FP5jS5mIuaAEnrxvpj2" : {
      "email" : "ffff@gmail.com",
      "fullname" : "Ffff",
      "fullname_lowercase" : "ffff",
      "profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/pinion-4896b.appspot.com/o/profile_image%2FFwUzqbn49FP5jS5mIuaAEnrxvpj2?alt=media&token=55649e15-4e6c-4b44-b804-1b4a9e8e4272"
    },
}

【问题讨论】:

  • 我知道它们是更新,但要求我们完成的代码太多了。请编辑问题并将代码减少到重现问题所需的最低限度。见和How to create a Minimal, Complete, and Verifiable example。此外,链接中断会使问题无效,因此将代码和结构作为文本包含在内。要获取您的 Firebase 结构,请使用 Firebase 控制台->导出 JSON 并复制粘贴您的结构的 sn-p。见images and links are evil
  • 当然 - 对不起,我是新手,所以我只是想通过提供尽可能多的信息来澄清,但我明白,我会减少它:)
  • 这样更好,但问题仍不清楚。通读解释,听起来您可以从 Firebase 成功加载您想要的数据,但您在某些时候遇到了冻结问题?这表明存在逻辑问题——可能是一个 var 被设置为 nil,或者一个循环没有迭代正确的次数。我建议在您的代码中放置一些断点并遍历它并分析您的变量以确保它们具有预期值或直到发生冻结 - 这将有助于缩小代码的哪些部分无法正常工作。
  • 感谢您的回复。我已经尝试过它,我认为错误可能来自:“如果 numFollowers
  • 这是一个奇怪的 if 语句。如果 numFollowers 3 则失败并测试 namesRemaining == 0。如果 numFollowers = 4 和 namesRemaining = 1 怎么办?不会执行任何语句 - 这是意图吗?更重要的是,numFollowers &lt;= 3 永远不会起作用,因为您没有更改 numFollowers 的值,即追随者节点由 .value 读取并假设有 4 个子节点。 let numFollowers = min(4, myKeyArray.count) 会将 numFollowers 设置为 4,之后似乎没有变化。

标签: ios swift firebase firebase-realtime-database real-time


【解决方案1】:

因此您可以使用observ 函数代替observeSingleEvent。 来自谷歌文档的示例: postRef.observe(DataEventType.value, with: { (snapshot) in let postDict = snapshot.value as? [String : AnyObject] ?? [:] // ... })

DataEventType(它是枚举)有下一个值: /// A new child node is added to a location. FIRDataEventTypeChildAdded, /// A child node is removed from a location. FIRDataEventTypeChildRemoved, /// A child node at a location changes. FIRDataEventTypeChildChanged, /// A child node moves relative to the other child nodes at a location. FIRDataEventTypeChildMoved, /// Any data changes at a location or, recursively, at any child node. FIRDataEventTypeValue

Observ 函数的工作方式类似于侦听器-观察者模式,所以不要忘记在观察事件时关闭订阅。

【讨论】:

  • 谢谢,这对您有所帮助,但仍有一些问题无法正常工作 - 我已对原始代码添加了更新,非常感谢您的帮助
  • 首先,你应该使用observeSingleEvent来获取单用户数据。另外,请分享您的 realtimeDB 数据结构。
  • 你能在类似 Json 的演示文稿中分享 realtimeDB 结构吗?
  • 当然,我已经添加了我的 firebase realtimeDB 的屏幕截图
猜你喜欢
  • 2021-09-14
  • 2016-12-17
  • 2016-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-10
  • 2019-07-14
相关资源
最近更新 更多