【问题标题】:firebase & swift - this class is not key value coding-compliant for the key -----firebase 和 swift - 此类不符合键的键值编码 -----
【发布时间】:2016-09-10 17:10:42
【问题描述】:

我知道还有其他类似的问题,但我认为我的问题在于我如何访问 firebase 而不是插座,因为我的错误出现在 @IBAction 函数中,该函数可以在错误发生之前被调用。

@IBAction func sign_in_out_tapped(sender : UIButton) {
    if let op_user = user {
        if (op_user.user_ref?.valueForKey("current_status"))! as! String == "OUT" {
            let sign_in_time = NSDate()
            op_user.user_ref?.childByAppendingPath("logins").updateChildValues([String(op_user.user_ref?.valueForKey("num_of_logins")! as! Int + 1): ["sign_in_time": sign_in_time]])
            signinout = SignInOutModel(sign_in_time: sign_in_time)

            op_user.user_ref?.updateChildValues(["current_status": "IN"])
        } else {
            signinout!.sign_out_time = NSDate()
            op_user.user_ref?.childByAppendingPath("logins").childByAppendingPath(String(user?.user_ref?.valueForKey("num_of_logins"))).updateChildValues(["sign_out_time": signinout!.sign_out_time!])

            signinout!.duration = (op_user.user_ref?.childByAppendingPath("logins").childByAppendingPath(String(user?.user_ref?.valueForKey("num_of_logins"))).valueForKey("sign_in_time")?.timeIntervalSinceNow)!
            op_user.user_ref?.childByAppendingPath("logins").childByAppendingPath(String(user?.user_ref?.valueForKey("num_of_logins"))).updateChildValues(["duration": signinout!.duration])
            op_user.user_ref?.updateChildValues(["total_hours": (Double((op_user.user_ref?.valueForKey("total_hours"))! as! NSNumber) + signinout!.duration)])
        }
} else {
        let sign_in_alert = UIAlertController(title: "Sign in.", message: "What is your first and last name?", preferredStyle: UIAlertControllerStyle.Alert)

        sign_in_alert.addTextFieldWithConfigurationHandler { textField in
            NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MainViewController.handleTextFieldTextDidChangeNotification(_:)), name: UITextFieldTextDidChangeNotification, object: textField)
        }

        func removeTextFieldObserver() {
            NSNotificationCenter.defaultCenter().removeObserver(self, name: UITextFieldTextDidChangeNotification, object: sign_in_alert.textFields![0])
        }

        let cancel_action = UIAlertAction(title: "Cancel", style: .Cancel) { action in
            print("Sign In Cancel Button Pressed")
            removeTextFieldObserver()
        }

        let save_action = UIAlertAction(title: "Save", style: .Default) { action in
            print("Sign Out Save Button Pressed")

            let textField = sign_in_alert.textFields![0] as UITextField

            if let user_name = textField.text {
                var not_found = false

                self.students_ref.childByAppendingPath(user_name).observeEventType(.Value, withBlock: { snapshot in

                    if (snapshot.value is NSNull) {
                        not_found = true
                    } else {
                        self.user = User(user_name: user_name)
                        self.user?.user_ref = self.students_ref.childByAppendingPath(user_name)
                        self.refresh_user_name_label()
                    }
                })

                if !not_found {
                    self.mentors_ref.childByAppendingPath(user_name).observeEventType(.Value, withBlock: { snapshot in

                        if (snapshot.value is NSNull) {
                            not_found = true
                        } else {
                            self.user = User(user_name: user_name)
                            self.user?.user_ref = self.mentors_ref.childByAppendingPath(user_name)
                            self.refresh_user_name_label()
                        }
                    })
                } else {
                    self.error_message("User not found. Please update Firebase.")
                }
            } else {
                self.error_message("Could not sign in.")
            }

            removeTextFieldObserver()
        }

        save_action.enabled = false

        AddAlertSaveAction = save_action

        sign_in_alert.addAction(cancel_action)
        sign_in_alert.addAction(save_action)

        self.presentViewController(sign_in_alert, animated: true, completion: nil)

        if let _ = user {
            let sign_in_time = NSDate()
            signinout = SignInOutModel(sign_in_time: sign_in_time)
        }
    }

    refresh_sign_in_out_button()
}

我相信错误出现在顶部,上面写着 "op_user.user_ref?.valueForKey("current_status"))! as String == "OUT"" 因为不仅错误说,

Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<Firebase 0x7fa12e0b5530> valueForUndefinedKey:]: this class is not key value coding-compliant for the key current_status.'

但是当通过调试器时,程序直到 "valueForKey("current_status")" 才终止。

任何帮助将不胜感激!谢谢!

编辑:我的火力基地:

{
  "mentors" : {
    "Ash Dreyer" : {
      "current_status" : "IN",
      "num_of_logins" : 0,
      "total_hours" : 0
    },
    "Donald Pinckney" : {
      "current_status" : "OUT",
      "num_of_logins" : 0,
      "total_hours" : 0
    },
    "Jasmine Zhou" : {
      "current_status" : "OUT",
      "num_of_logins" : 0,
      "total_hours" : 0
    },
    "Michael Corsetto" : {
      "current_status" : "OUT",
      "num_of_logins" : 0,
      "total_hours" : 0
    }
  },
  "students" : {
    "Bryton Moeller" : {
      "current_status" : "OUT",
      "num_of_logins" : 0,
      "total_hours" : 0
    },
    "Kelly Ostrom" : {
      "current_status" : "OUT",
      "num_of_logins" : 0,
      "total_hours" : 0
    },
    "Kyle Stachowicz" : {
      "current_status" : "OUT",
      "num_of_logins" : 0,
      "total_hours" : 0
    },
    "Wesley Aptekar-Cassels" : {
      "current_status" : "OUT",
      "num_of_logins" : 0,
      "total_hours" : 0
    }
  }
}

编辑:

我的项目的目标是创建一个登录/注销应用。我的导师希望其他人能够查看某人是否已登录,并希望跟踪某人总共登录了多长时间(例如他们是否在商店中达到了 100 小时或其他时间。)

【问题讨论】:

  • op_user.user_ref 的类型是什么? current_status 是一个有效的密钥吗?
  • 火力基地。是的,我在这里贴一张我的钥匙截图
  • 您能否以文本形式发布您的 Firebase 代码以及您的 Firebase 结构(Firebase 仪表板->导出)。请不要使用屏幕截图,因为它会导致我们不得不在我们的答案中重新输入它。此外,还有很多可选项的展开 - 这使代码过于复杂。而且...您是否只是想查看带有 current_status 键的用户字典是否“out”?
  • @Jay 对不起,我对快速编程真的很陌生!是的,我正在尝试查看 current_status 是否为 OUT。对不起。
  • 截图不见了!谢谢。您还可以发布用于读取 Firebase 数据的代码吗?

标签: ios swift firebase firebase-realtime-database


【解决方案1】:

您的问题是您尝试访问 Firebase 参考数据的方式。 valueForKey 不是正确的方法。您需要做以下两件事之一:

  1. 首先将您的 firebaseSnap.value 转换为字典,然后使用 dict[key] 语法。
  2. Snapshot.childSnapshotForPath("current_status").value

我会推荐 2 号,作为最干净的方法。但是,如果您需要大量访问引用,您可能希望转换为字典,因为这样访问它看起来会更好。

注意:这两个都需要一个 firebase 事件侦听器来获取 firebase 快照。

如果您有任何问题,请告诉我,祝您好运!

【讨论】:

    【解决方案2】:

    根据您的后续 cmets,以下几点可能会有所帮助。请原谅冗长的答案,但只是试图帮助减少和简化您编写的代码量。

    一般来说,从数据中分离键是一个很好的模型。原因是:如果用户更改了他们的名字怎么办?他们结婚了,所以姓氏不同,决定他们喜欢叫吉姆而不是詹姆斯等。如果你用他们的名字作为关键,它是不可改变的,你提到的任何其他地方也会被卡住。如果您将名称设为子节点,则可以随时更改它而不会影响其他数据。

    第一步是把结构改成这样

    {
      "mentors" : {
         "uid_0" : {
           "user_name": "Ash Dreyer",
           "current_status" : "IN",
           "num_of_logins" : 0,
           "total_hours" : 0
        },
         "uid_1" : {
           "user_name": "Donald Pinckney",
           "current_status" : "OUT",
           "num_of_logins" : 0,
           "total_hours" : 0
        },
    

    uid_0、uid_1 等由 Firebase 在创建用户时创建,可以从 authData.uid 中检索。这是您存储在 /mentors(或 /users)节点中的每个用户的关键数据。

    当用户登录时,您有两个选择:如果您不需要他们的数据,您可以只更新 current_status 节点。您知道具体的节点名称,因为它是它们的 auth.uid。

    let ref = /mentors node
    let thisUser = ref.childByAppendingPath(auth.uid)
    let thisUsersStatusRef = thisUser.childByAppendingPath("current_status")
    thisUsersStatusRef.setValue("In")
    

    对时间戳做同样的事情。

    如果您需要在 UI 中显示他们的名字,只需通过 observeSingleEvent 读取他们的数据,并更新当前状态和时间戳。

    let ref = /mentors node
    let thisUser = ref.childByAppendingPath(auth.uid)
    
    ref.observeSingleEventOfType(.Value, withBlock: { snapshot
    
      //read the user data from the snapshot and do whatever with it
      let name = snapshot.value["user_name"] as? String
      print(name!)  
    
      //now update the status
      thisUsersStatusRef.setValue("In")
      //and the timestamp
    }
    

    用户退出时,只需计算小时数,设置current_status为out并写入时间戳

    thisUsersStatusRef.setValue("Out")
    thisUsersHoursRef.setValue(hours)
    thisUsersTimeStamp.setValue(timestamp)
    

    这里的大局是,如果您在用户登录时读取用户数据,您可以预先获取所有信息来计算小时数等,因为它可以存储在变量中,因此当他们注销时,进行计算和写。因此,它基本上只命中 Firebaes 两次(登录时一次,注销时一次)。

    最后一件事是每个用户都应该观察 /mentors 节点中的 childAdded、childChanged 或 childRemoved 事件(不是值)。有了这些观察者,当添加、编辑或更改用户时,所有用户都会收到该单个数据节点的通知,并且可以相应地更新他们的 UI。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-06-23
      • 1970-01-01
      • 2017-11-29
      • 2017-10-15
      • 1970-01-01
      相关资源
      最近更新 更多