【问题标题】:Easiest way to increment a data point in Firebase?在 Firebase 中增加数据点的最简单方法?
【发布时间】:2016-06-22 03:36:07
【问题描述】:

我在 Firebase 中增加一条数据时遇到问题。

Firebase {
    clickedCounter: 0
}

这是我的代码:

@IBAction func plus(sender: UIButton) {
        FIRDatabase.database().reference().child("clickedCounter").observeEventType(.Value) { (snap: FIRDataSnapshot) in
            let value = FIRDatabase.database().reference().child("clickedCounter") as? NSNumber
            let increment = ((value?.intValue)! + ((1 as? NSNumber)?.intValue)!) as? NSNumber
            FIRDatabase.database().reference().child("clickedCounter").setValue()
            self.clickLabel.text = snap.value?.description as String!
        }
    }

我也试过了:

@IBAction func plus(sender: UIButton) {
        FIRDatabase.database().reference().child("clickedCounter").observeEventType(.Value) { (snap: FIRDataSnapshot) in
            FIRDatabase.database().reference().child("clickedCounter").setValue((snap.value?.description)! + 1)
            self.clickedLabel.text = snap.value?.description as! String!
        }
    }

首先我的警告是:

Cast from Int32 to NSNumber always fails

Conditional cast from NSNumber to NSNumber always succeeds

Cast from FIRDatabaseReference to NSNumber always fails

运行后,let increment.... 出现错误:Thread 1: EXC_BAD_INSTRUCTION

第二个错误是:

Binary operator + cannot be applied to operands of the type String and Int

  1. 当我认为我在 Firebase 中将 snap.value?.description 定义为一个 Int 时,我很困惑我的 snap.value?.description 如何是一个字符串。

  2. 为什么总是成功时我会收到警告?

  3. 有没有更好的方法来做到这一点?

谢谢!

【问题讨论】:

    标签: swift firebase firebase-realtime-database


    【解决方案1】:

    为什么不呢(v2.x Firebase 代码,但你明白了)

    counterRef.observeSingleEventOfType(.Value, withBlock: { snapshot in
         let valString = snapshot.value
         var value = valString.intValue
         value = value + 1
         counterRef.setValue("\(value)")         
    })
    

    如果这将被多个用户频繁更新,也可以利用交易块。

    【讨论】:

    • 这行得通,谢谢。不过还有一个问题。当我单击加号时,动作继续运行,一遍又一遍地使数字 +1。你知道解决办法吗?
    • 其实很抱歉我没有完全实现你的代码。 observeSingleEventOfType 和 observeEventType 有什么区别?我应该什么时候使用?
    • observeSingleEventOfType 读取一个节点一次,而 observeEventType 将观察者附加到该节点。它通知应用程序一次,然后持续监控更改(添加、更改、删​​除)并在发生更改时通知应用程序。有关详细信息,请参阅 Firebase 指南 Retrieve Data。通常,如果您只想要一条数据并且不需要知道它是否发生变化,请使用observeSingleEventOfType,如本用例所示。如果您想了解更改,例如在聊天类型应用程序中,请使用 observeEventType
    • 如果你开启了数据持久化——这种增量根本不可靠。如果计数器从其他地方更改 - 这个一次性观察者将继续返回旧值。旧的(缓存的)值将在实际值更改后很长时间返回。
    • @Vitalii 不知道这意味着什么 - 显然,如果一个应用程序依赖于 current data 你不会像 any 数据那样打开持久性从缓存中读取时会过时,对吗?例如,如果一个应用程序正在显示地理位置数据并且用户穿过一条长隧道,他们不希望它继续显示 10 分钟前所在位置的错误数据。在这种情况下,应用程序应指示“位置数据不可用”。
    【解决方案2】:

    尝试使用事务来安全地获取当前数据并增加它。 请参阅此处文档中的示例: https://firebase.google.com/docs/database/ios/save-data#receive_a_completion_callback

    【讨论】:

    • 这是网页版,我没找到swift版。
    【解决方案3】:

    如果数据库已关闭持久性,请按照@Jay 的回答。

    但是如果您的数据库已打开持久性,使用observeSingleEventOfType 递增的常用方法根本不起作用 - 它会根据旧值递增,最终会弄乱一切。

    幸运的是,多亏了 Natural Lam 在他的文章 here 中描述的发现,仍然有一种方法可以在持久性打开的情况下可靠地增加。诀窍是强制 Firebase 通过 keepSynced 和写入操作的组合来同步数据。这是一个对我来说如何工作的示例:

    func increaseUnreadChatsFor(chatId: String) {
        let chatRef = self.ref.child("chats/\(chatId)")
        chatRef.keepSynced(true)
        chatRef.child("dummy").setValue("dummy") { _, _ in
            chatRef.child("dummy").removeValue()
            chatRef.keepSynced(false)
            chatRef.child("unread").observeSingleEvent(of: .value, with: { snapshot in
                 if !snapshot.exists() { // no unread record yet, creating one
                    chatRef.child("unread").setValue(1)
                 } else if let unread = snapshot.value as? Int { // record already exists, incrementing it
                    chatRef.child("unread").setValue(unread + 1)
                 }
             })
        }
    }
    

    当然不能保证离线工作。

    另一种选择是再次配置相同的数据库,但这次关闭持久性并使用该 firebase 实例进行增量(显然只能在线工作)。如何做到这一点你可以阅读我的回答here

    【讨论】:

      猜你喜欢
      • 2010-10-14
      • 1970-01-01
      • 2021-11-12
      • 2019-07-06
      • 2016-04-05
      • 1970-01-01
      • 2011-08-05
      • 1970-01-01
      相关资源
      最近更新 更多