Firebase & swift - this class is not a key value compatible with the encoding for the key -----

I know there are other similar questions, but I think my problem is with the way I access firebase and not the socket, because my error is with the @IBAction function, which can be called before it happens error.

@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() } 

I believe that the error is at the top where it says: "op_user.user_ref? .ValueForKey (" current_status "))! As String ==" OUT ", because it not only talks about the error,

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

but when passing through the debugger, the program does not end until the value "valueForKey (" current_status ")".

Any help would be appreciated! Thanks!

EDIT: My firebase:

 { "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 } } } 

EDIT:

The goal of my project is to create a sign in / out application. My mentor wants others to see if someone has signed up or not, and wants to keep track of how much time has passed in general, someone has signed up (for example, if they reached 100 hours in a store or something like that .)

+6
source share
2 answers

Your problem is how you are trying to access the data of your Firebase link. valueForKey is the wrong way to do this. You need to do one of two things:

  • First add your firebaseSnap.value to the dictionary, and then use the dict [key] syntax.
  • Snapshot.childSnapshotForPath ("CURRENT_STATUS"). Value

I would recommend number 2 as the cleanest way to do this. But if you need to access the link a lot, you might want to use a dictionary, because access to it will look better.

NOTE. Both of them require a firebase event listener to capture a firebase snapshot.

Let me know if you have any questions and good luck!

+6
source

Based on your subsequent comments, here are a few things that might help. Forgive the long answer, but just try to help reduce and simplify the amount of code you write.

In general, disassociating keys from data is a good model. The reason for this is: what if the user changes his name? They marry with a different surname, decide that they like to call Jim instead of James, etc. If you use your name as a key, it is not mutable, and in any other place that you access, it will also depend on it. If you make the name a child node, you can change it at any time without affecting other data.

The first step is to change the structure to something like this

 { "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, etc. are created by Firebase when the user is created and can be obtained from authData.uid. This is a great piece of data to use in a key for each user that you store with your / mentors (or / users) node.

When a user logs in, you have several options: if you do not need their data, you can simply update the current_status node. You know the specific name of the node, since this is their auth.uid.

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

and do the same for the timestamp.

If you need to display their name in the user interface, just read their details through watchSingleEvent and update the current status and timestamp.

 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 } 

When the user subscribes, all you have to do is calculate in a few hours, set current_status to exit and record the timestamp

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

The big picture here is that if you read the user data when you log in, you have all the information ahead to calculate the hours, etc., since it can be stored in a variable, so when they log out, do calculation and write. This way, it essentially only hits Firebaes twice (once when they log in and once when they log out).

The last thing that every user should observe is / mentors node for the events childAdded, childChanged or childRemoved (NOT Value). With these observers, when a user is added, edited or changed, all users are notified with this single data node and can update their interface accordingly.

+2
source

All Articles