Using value(forKey: String) gives an error - ios

I am trying to retrieve data from Firebase but I've run into a problem and I can't seem to solve it. Here is my code:
Database.database().reference().child("Users").child(userID!).observeSingleEvent(of: .value) { (snapshot) in
if let name = snapshot.value(forKey: "name") as? String {
userName = name
print(userName)
}
if let username = snapshot.value(forKey: "Username") as? String {
userUsername = username
print(userUsername)
}
if let email = snapshot.value(forKey: "Email") as? String {
userEmail = email
print(userEmail)
}
}
Running this gives me an error:
'NSUnknownKeyException', reason: '[
valueForUndefinedKey:]: this class is not key value coding-compliant
for the key Username.'
Here is a picture of my database:

First Convert snapshot value to Dictionary and then get value from it like below
Database.database().reference().child("Users").child(userID!).observeSingleEvent(of: .value) { (snapshot) in
if let data = snapshot.value as? [String: String] {
let name = data["name"]!
let email = data["email"]!
let userName = data["Username"]!
}

You need to cast snapshot.value which of type Any to [String:String]
Database.database().reference().child("Users").child(userID!).observeSingleEvent(of: .value) { (snapshot) in
guard let res = snapshot.value as? [String:String] else { return }
if let name = res["name"] {
userName = name
print(userName)
}
if let username = res["Username"] {
userUsername = username
print(userUsername)
}
if let email = res["Email"] {
userEmail = email
print(userEmail)
}
}

Related

Variable username is not updated after call to Firebase

var username: String? = nil
self.ref.child("users").observeSingleEvent(of: .value, with: { (snapshot) in
let usersProfile = snapshot.value as? NSDictionary
let userProfile = usersProfile![userID] as? NSDictionary
username = userProfile!["username"] as! String
}) { (error) in
print(error.localizedDescription)
}
print(username)
Why is the variable username not updated in the end?
You can try like this
var username: String? = nil
self.ref.child("users").observeSingleEvent(of: .value, with: { (snapshot) in
if let usersProfile = snapshot.value as? NSDictionary, let userProfile = usersProfile![userID] as? NSDictionary, let name = userProfile!["username"] as? String {
username = name
}
}) { (error) in
print(error.localizedDescription)
}
print(username)

App Crashes When Observing Real Time Chat Data with Firebase-iOS

I am currently learning Swift and I decided to make an iOS messaging app using Firebase. I am using JSQMessageViewController as my chat template and everything is working fine except for the fact that the app crashes when two users talking to each other are in the chat room at the same time. I am getting this error near the bottom of the function below: "Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)"
Here is my code for observing and retrieving message data. I call this everytime the view appears:
private func observeMessages() {
messageRef = ref.child("ChatRooms").child(chatRoomId!).child("Messages")
let messageQuery = messageRef.queryLimited(toLast:25)
newMessageRefHandle = messageQuery.observe(.childAdded, with: { (snapshot) in
let messageData = snapshot.value as! Dictionary<String, AnyObject>
if let data = snapshot.value as? [String: AnyObject],
let id = data["sender_id"] as? String,
let name = data["name"] as? String,
let text = data["text"] as? String,
let time = data["time"] as? TimeInterval,
!text.isEmpty
{
if id != uid! {
let updateRead = ref.child("ChatRooms").child(self.chatRoomId!).child("Messages").child(snapshot.key)
updateRead.updateChildValues(["status":"read"])
}
if let message = JSQMessage(senderId: id, senderDisplayName: name, date: Date(timeIntervalSince1970: time), text: text)
{
self.messages.append(message)
self.finishReceivingMessage()
}
}else if let id = messageData["senderId"] as! String!,
let photoURL = messageData["photoURL"] as! String! { // 1
if let mediaItem = JSQPhotoMediaItem(maskAsOutgoing: id == self.senderId) {
self.addPhotoMessage(withId: id, key: snapshot.key, mediaItem: mediaItem)
if photoURL.hasPrefix("gs://") {
self.fetchImageDataAtURL(photoURL, forMediaItem: mediaItem, clearsPhotoMessageMapOnSuccessForKey: nil)
}
}
}else {
print("Error! Could not decode message data")
}
})
updatedMessageRefHandle = messageRef.observe(.childChanged, with: { (snapshot) in
let key = snapshot.key
//I am getting an error on this line
let messageData = snapshot.value as! Dictionary<String, String>
if let photoURL = messageData["photoURL"] as String! {
// The photo has been updated.
if let mediaItem = self.photoMessageMap[key] {
self.fetchImageDataAtURL(photoURL, forMediaItem: mediaItem, clearsPhotoMessageMapOnSuccessForKey: key)
}
}
})
}
Curious to what I might be doing wrong here. All help is appreciated!

Initialize an object to take in optional values on Firebase with Swift

I'm comfortable with initializing objects in general but my method only seems to work when all parameters must exist on the database. I have looked at this which works. But I now don't know how to initialize it with a nest array.
This is how I would normally initialise an object:
class User {
var firstName: String
var lastName: String
var summary: String?
var groups = [Group]()
var ref: DatabaseReference?
var key: String
init?(from snapshot: DataSnapshot) {
let snapshotValue = snapshot.value as? [String: Any]
guard let firstName = snapshotValue?["firstName"] as? String, let lastName = snapshotValue?["lastName"] as? String, let summary = snapshotValue?["summary"] as? String else { return nil }
self.firstName = firstName
self.lastName = lastName
self.summary = summary
self.key = snapshot.key
self.groups(snapshot: snapshot.childSnapshot(forPath: "groups"))
}
func groups(snapshot: DataSnapshot) {
for child in snapshot.children {
guard let group = child as? DataSnapshot else { continue }
}
}
Just don't make the optional properties a part of that guard (that's what prevents the execution to finish it:
init?(from snapshot: DataSnapshot) {
let snapshotValue = snapshot.value as? [String: Any]
guard let firstName = snapshotValue?["firstName"] as? String,
let lastName = snapshotValue?["lastName"] as? String else { return nil }
self.firstName = firstName
self.summary = snapshotValue?["summary"] as? String
self.key = snapshot.key
self.groups(snapshot: snapshot.childSnapshot(forPath: "groups"))
}
Optionally, you can use if let syntax:
if let summary = snapshotValue?["summary"] as? String {
self.summary = summary
}
But in this case this is simpler:
self.summary = snapshotValue?["summary"] as? String

Firebase NSNull Exception while taking Snapshot of Data

i was making a Firebase practice app and i encountered this problem. Where i got NSNull exception while capturing a value from Firebase database. Here is the code
user = FIRAuth.auth()?.currentUser
ref = FIRDatabase.database().reference()
let userid = user.uid
if userid != nil
{
print("User Nid \(userid)")
ref.child("users").child(userid).observe(.value, with: {
(snapshot) in
if(snapshot.exists()){
var user_details = snapshot.childSnapshot(forPath: "\(userid)")
var user_det = user_details.value as! Dictionary<String, String>
print("User Name \(user_det["name"])")
}
else{
print("Does not exist")
}
})
}
and here is the database.
uid
user-details
name: "Salman"
propic: "picurl"
Could you try with this way
ref.child("users").child(userID!).observeSingleEvent(of: .value, with: { (snapshot) in
// Get user value
let value = snapshot.value as? NSDictionary
if let userDetail= value?["user-details"] as? [String:Any] {
// let username = value?["name"] as? String ?? ""
let username = userDetail["name"] as? String ?? ""
}
}) { (error) in
print(error.localizedDescription)
}

Return from initializer without initializing all stored properties Xcode 8

I upgraded to Xcode 8 and my app stopped working and I have been able to fix everything but this one error. I have been looking online and I have not found a fix for this error. Any Help would be appreciated.
Here is the code:
struct Party {
let itemRef:FIRDatabaseReference?
//
let userID:String!
let name:String!
let title:String!
let body:String!
init (userID:String, name:String, title:String = "", body:String) {
self.userID = userID
self.name = name
self.title = title
self.body = body
self.itemRef = nil
}
init (snapshot:FIRDataSnapshot) {
userID = snapshot.key
itemRef = snapshot.ref
if let titl = snapshot.value as? [String:AnyObject] {
for child in titl{
let shotKey = snapshot.children.nextObject() as! FIRDataSnapshot
if let title = child.value as? [String:AnyObject]{
let title = title["title"]
print(title)
}
}
}else{
title = "Failed To Display Title"
}
if let user = snapshot.value as? [String:AnyObject] {
for child in user{
let shotKey = snapshot.children.nextObject() as! FIRDataSnapshot
if let name = child.value as? [String:AnyObject]{
let name = name["name"]
print(name)
}
}
}else{
name = "Failed To Display Name"
}
if let partyBody = snapshot.value as? [String:AnyObject]{
for child in partyBody{
let shotKey = snapshot.children.nextObject() as! FIRDataSnapshot
if let body = child.value as? [String:AnyObject]{
let body = body["body"]
print (body)
}
}
}else{
body = "Failed To Display Time"
}
}
func toAnyObject() -> Any {
return ["title":title, "name":name, "body":body]
}
}
Your second init(snapshot:) function doesn't set the name, title, and body properties under certain conditions.
You have this code for the title:
if let titl = snapshot.value as? [String:AnyObject] {
for child in titl{
let shotKey = snapshot.children.nextObject() as! FIRDataSnapshot
if let title = child.value as? [String:AnyObject]{
let title = title["title"]
print(title)
}
}
}else{
title = "Failed To Display Title"
}
This code only sets the title property in the else clause. The four references to title inside the if part are references to local variables named title, not the property named title. So the compiler complains you never set the title property because there is a possible code path where it isn't set.
You have the same issue for name and body.

Resources