Finding nil when reading from database - swift

When trying to read from Firebase I get
Fatal error: Unexpectedly found nil while unwrapping an Optional value
Code for reading the database:
ref = Database.database().reference().child("userDatabases").child(userID!).child("-Lk__eup2Z7WR-iqtXkI").child("-Lk__gmhOTWfVzEPVo2t")
ref?.observeSingleEvent(of: .value, with: { (snapshot) in
for child in snapshot.children.allObjects as! [DataSnapshot] {
let dict = child.value as? [String : AnyObject] ?? [:]
self.objectProducer.append(dict["objectProducer"] as! String)
self.objectType.append(dict["objectType"] as! String)
self.objectAmount.append(dict["amount"] as! String)
self.objectMeasureUnit.append(dict["unit"] as! String)
}
})
If I try to print for example: print(dict["objectProducer"]) I get the correct result.
The FirebaseStructure I´m trying to read from looks like this:
"-Lk__eup2Z7WR-iqtXkI" : {
"-Lk__gmhOTWfVzEPVo2t" : {
"5740700998485" : {
"amount" : "330",
"objectProducer" : "Coca Cola",
"objectType" : "Zero",
"unit" : "Milliliter"
},
"createdOn" : "24-7-2019 at: 22:5:35",
"listID" : "-Lk__gmhOTWfVzEPVo2t",
"name" : "Test"
},
What is going wrong here?

in my opinion, change this line of code
let dict = child.value as? [String : AnyObject] ?? [:]
to:
guard let dict = child.value as? [String: AnyObject] else { return }
then you sould not getting error.
hop this help.

I think the crash due to self.objectAmount.append(dict["amount"] as! String).
You try execute the code: self.objectAmount.append(dict["amount"] as! Int)

Related

Fetch multi level node from Firebase

I am trying to fetch the "friends" from the node to be able to show them in UICollectionView afterwards. I now realized that I have to use a struct and place the Friends array inside. I am struggling now to understand how to fetch them into that array (you can see it at the bottom of the post). Data is stored in a firebase node. How can I grab the data and what would be the procedure to place it in UICollectionView afterwards? This is my function so far to retrieve.
UPDATE: (I think I am fetching correctly now but I don't get any results. Is there something that I should do in collection view? or what am I doing wrong?)
UPDATE: Here is my code for post fetching:
func fetchPosts3() {
ref.child("Users_Posts").child("\(unique)").queryOrderedByKey().observeSingleEvent(of: .value, with: { snapshot in
print(snapshot)
if snapshot.value as? [String : AnyObject] != nil {
let allPosts = snapshot.value as! [String : AnyObject]
self.posts.removeAll()
for (_, value) in allPosts {
if let postID = value["postID"] as? String,
let userIDDD = value["userID"] as? String
{
//ACCESS FRIENDS
ref.child("Users_Posts").child("\(unique)").child(postID).child("friends").queryOrderedByKey().observeSingleEvent(of: .value, with: { (snap) in
print("FRIENDS: \(snap.childrenCount)")
//var routine = self.postsWithFriends[0].friends
for friendSnap in snap.children {
if let friendSnapshot = friendSnap as? DataSnapshot {
let friendDict = friendSnapshot.value as? [String: Any]
let friendName = friendDict?["name"] as? String
let friendPostID = friendDict?["postID"] as? String
let postsToShow = PostWithFriends(id: userIDDD, friends: [Friend(friendName: friendName!, friendPostID: friendPostID!)])
self.postsWithFriends.append(postsToShow)
print("COUNTING: \(self.postsWithFriends.count)")
// then do whatever you need with your friendOnPost
}
}
})
}
}
//GET LOCATION
self.collectionView?.reloadData()
self.posts.sort(by: {$0.intervalPosts! > $1.intervalPosts!})
}
})
ref.removeAllObservers()
}
That's how the data looks at the database:
{
"-LN2rl2414KAISO_qcK_" : {
"cellID" : "2",
"city" : "Reading",
"date" : "2018-09-23 00:41:26 +0000",
"friends" : {
"UJDB35HDTIdssCtZfEsMbDDmBYw2" : {
"name" : "Natalia",
"postID" : "-LN2rl2414KAISO_qcK_",
"userID" : "UJDB35HDTIdssCtZfEsMbDDmBYw2"
},
"Vyobk7hJu5OGzOe7E1fcYTbMvVI2" : {
"name" : "Gina C",
"postID" : "-LN2rl2414KAISO_qcK_",
"userID" : "Vyobk7hJu5OGzOe7E1fcYTbMvVI2"
}
},
}
}
And this is my object that's stored into array
struct PostWithFriends {
var postID : String?
var friends: [Friend]
}
class Friend : NSObject {
var friendName: String?
var friendUserID: String?
var postID: String?
init(friendName: String, friendPostID: String) {
self.friendName = friendName
self.postID = friendPostID
}
}
Replace this
if let friend = snap.value as? [String : AnyObject] {
}
With this:
for friendSnap in snap.children {
if let friendSnapshot = friendSnap as? FIRDataSnapshot {
let friendOnPost = FriendOnPost()
let friendDict = friendSnapshot.value as? [String: Any]
friendOnPost.name = friendDict?["name"] as? String
friendOnPost.friendUserID = friendDict?["userID"] as? String
friendOnPost.postID = friendDict?["postID"] as? String
// then do whatever you need with your friendOnPost
}
}

How to retrieve data from all the Users using Firebase and Swift

i have a firebase databank looking like this(Json):
{
"user" : {
"UVHpZfD60EWcYDbeV60ENqXaioA3" : {
"email" : "thisisanothertest#gg.gg",
"location" : {
"latitude" : 37.785834,
"longitude" : -122.406417
},
"profile" : {
"alter" : "23",
"geschlecht" : "männlich",
"name" : "Mario1"
}
},
"nEsKd9uIOnSmVuMbAK0K2X1Dz6A3" : {
"email" : "thisisatest#gg.gg",
"location" : {
"latitude" : 37.785834,
"longitude" : -122.406417
},
"profile" : {
"alter" : "23",
"geschlecht" : "männlich ",
"name" : "Mario"
}
}
}
Problem:
Now i would like to get the Locations from all the users (latitude and longitude) to place them later on on a Map.
I can get the location for a single user realy easy by doing the below code. But how can i get the data from all the users at once?
var ref: DatabaseReference!
ref = Database.database().reference()
let userID = Auth.auth().currentUser?.uid
ref.child("user").child(userID!).child("location").observeSingleEvent(of: .value, with: { (snapshot) in
// Get user value
let value = snapshot.value as? NSDictionary
let lat = value?["latitude"] as? Double ?? 0.0
let long = value?["longitude"] as? Double ?? 0.0
I found a similar question already here
So i tried that code from the above link:
let usersRef = ref.child("users")
usersRef.observeSingleEvent(of: .value, with: { (snapshot) in
for snap in snapshot.children {
let userSnap = snap as! FIRDataSnapshot
let uid = userSnap.key //the uid of each user
let userDict = userSnap.value as! [String:AnyObject] //child data
let location = userDict["Location"] as! String
print("key = \(uid) is at location = \(location)")
}
})
But with that pice of code i was only able to get all the email adresses. By changing the "Location" to "email". How can i go down one more node to access the "location" node and get the latitude and longitude of all the users?
Thank you :)
Looks like you misspelled the location key for your dictionary:
let location = userDict["Location"] as! [String: AnyObject]
Replace it with:
let location = userDict["location"] as! [String: AnyObject]
You can always put a breakpoint at the print line and see what your location dictionary looks like with po location in console.
As you can see in your data location is stored as another object, so you have to cast it as Dictionary => [String:AnyObject]
for snap in snapshot.children {
let userSnap = snap as! FIRDataSnapshot
let uid = userSnap.key //the uid of each user
let userDict = userSnap.value as! [String:AnyObject] //child data
let location = userDict["location"] as! [String:AnyObject]
print("key = \(uid) is at location = \(location)")
}

Could not cast value of type __NSCFString

I am trying out FCM messaging service. I have setup everything perfecting. When I receive message from FCM I get the following error. I am not sure what is wrong here:
AnyHashable("google.c.a.c_id"): 1586592282379086000, AnyHashable("gcm.message_id"): 0:1515418580276498%f4373656f4373656]
Could not cast value of type '__NSCFString' (0x1b4c70040) to 'NSDictionary' (0x1b4c70b80).
2018-01-08 19:06:21.198548+0530 Ozone[1067:540436] Could not cast value of type '__NSCFString' (0x1b4c70040) to 'NSDictionary' (0x1b4c70b80).
The strange part is I created a seperate Push Notification App and put the same code, it is working there. What could be wrong here?
Here is the piece code: I am getting the error in let d : [String : Any].....line
UNNotificationPresentationOptions) -> Void) {
print("Handle push from foreground\(notification.request.content.userInfo)")
let dict = notification.request.content.userInfo["aps"] as! NSDictionary
let d : [String : Any] = dict["alert"] as! [String : Any]
let body : String = d["body"] as! String
let title : String = d["title"] as! String
print("Title:\(title) + body:\(body)")
self.showAlertAppDelegate(title: title,message:body,buttonTitle:"ok",window:self.window!)
}
Can some one help me with this? I know it is very general error but not sure why this is coming as it is working fine in another app.
Thanks!
alert key can be string or dictionary (depends on your server). You can try this.
if let dict = notification.request.content.userInfo["aps"] as? [String : Any] {
if let d = dict["alert"] as? [String : Any],
let body = d["body"] as? String,
let title = d["title"] as? String {
print("Title:\(title) + body:\(body)")
} else if let body = dict["alert"] as? String {
print("body:\(body)")
}
}
And also you should avoid force casting and don't use NSDictionary in swift.

Retrieve / read data from Firebase database

I am using this code to retrieve data from a Firebase database. However, I am only able to pull one variable at a time. Can you please help me find a way to pull the others (student names, title etc.) and save them to an object arrayList?
{
"projects" : [
1, {
"answer1" : false,
"answer2" : true,
"answer3" : true,
"campus" : "Science Academy",
"category" : "LifeScience",
"question1" : "This is question 1",
"question2" : "This is question 2",
"question3" : "This is question 3",
"student1" : "john",
"student2" : "Kyle",
"title" : "Amazon Forest"
}
]
}
var ref : DatabaseReference?
var handle : DatabaseHandle?
ref = Database.database().reference()
handle = ref?.child("projects").child("1").child(question1).observe(.value, with: { (snapshot) in
if let question = snapshot.value as? String {
print(question)
}
})
IF your database has more that just projects/1 and you're wanting to access projects/1-2-3-4 etc. then you'll want to do something like this:
let reference = Database.database().reference()
reference.child("projects").observe(.childAdded, with: { (snapshot) in
let key = snapshot.key // THIS WILL GET THE PROJECT THAT IT'S IN. 1, 2, 3, 4 etc.
guard let dictionary = snapshot.value as? [String: AnyObject] else { return }
let answer1 = dictionary["answer1"] as? Bool
let campus = dictionary["campus"] as? String
}, withCancel: nil)
IF you're wanting to simple get a hold of all the values inside of project/1 and not just the questions, you'll want to do something like this:
let reference = Database.database().reference()
reference.child("projects").child("1").observeSingleEvent(of: .value, with: { (snapshot) in
let key = snapshot.key // THIS WILL GET THE PROJECT THAT IT'S IN. 1, 2, 3, 4 etc.
guard let dictionary = snapshot.value as? [String: AnyObject] else { return }
let answer1 = dictionary["answer1"] as? Bool
let campus = dictionary["campus"] as? String
}, withCancel: nil)

cannot subscript a value of type 'inout [AnyHashable: Any

Sorry super noobie here trying to compile this and it's the last error I'm trying to fix.
let optionalString0 = formatter.stringFromNumber(NSNumber(localNotification.userInfo!["pokemonId"]as! Int))
if optionalString0 != nil {
imagen.setImage(UIImage(named: optionalString0!))
I think error is due to this statement:
NSNumber(localNotification.userInfo!["pokemonId"]as! Int)
I tried this in playground to reproduce the error:
var dict = [1: "10", "t": 100] as [AnyHashable : Any]
func foo( paramDict: inout [AnyHashable : Any]) {
print(NSNumber(paramDict["t"] as! Int)) //getting the same error on this line
}
foo(paramDict: &dict)
In above code I get the same error on print statement
I solved this problem by modifying the above code like this:
var dict = [1: "10", "t": 100] as [AnyHashable : Any]
func foo( paramDict: inout [AnyHashable : Any]) {
if let number = paramDict["t"] as? NSNumber {
print(number)
}
}
foo(paramDict: &dict)
so in your case you modify your code like this:
if let number = localNotification.userInfo?["pokemonId"] as? NSNumber {
let optionalString0 = formatter.string(from: number)
if optionalString0 != nil {
imagen.setImage(UIImage(named: optionalString0!))
}
}
Note: You can modify above code like this: (Its not related to the error in question but just a different way to write the above code(may be better))
if let number = localNotification.userInfo?["pokemonId"] as? NSNumber, let optionalString0 = formatter.string(from: number) as? String {
imagen.setImage(UIImage(named: optionalString0))
}
Thanks all for the help and feedback!
this looks like it works for so far
if let number = localNotification.userInfo?["pokemonId"] as? NSNumber, let optionalString0 = formatter.string(from: number) as? String {
imagen.setImage(UIImage(named: optionalString0))
}