I'm trying to pull an int from my firebase db however when I try and set my variable it returns nil.
ref = Database.database().reference()
let UserUID = Auth.auth().currentUser?.uid as? String
ref.child("users").child(UserUID!).child("MaxVal").observeSingleEvent(of:
.value, with: { (snapshot) in
let snap = snapshot.value as? Int
self.MaxValFB = snap! //this returns nil
}) { (error) in
print(error.localizedDescription)
}
Any help apreiciated!
EDIT: upon printing its result it returns
Optional( null)
also here is the db json file
{
"users" : {
"Optional(\"njcfCQaIIhZS9qrqM9OFLqTS7yA2\")" : {
"MaxVal" : 1
}
}
}
I think the problem is this "Optional(\"njcfCQaIIhZS9qrqM9OFLqTS7yA2\")" , when you are saving the data to firebase , you are giving it the id without unwrapping the optional and when you get the value you are unwrapping it like UserUID! , so it gives "njcfCQaIIhZS9qrqM9OFLqTS7yA2" , hence these are two different values.
So I think you should unwrap the userid when you save the data to firebase or try to get it without unwrapping i.e child(UserUID) without ! , although I would suggest to go with the first option.
Related
We are currently making an iOS app and with firebase as its database. Please find below our code.
static func getTilesPerRow () -> Int{
let user = Auth.auth().currentUser
guard let uid = user?.uid else {
return -2
}
var ref: DatabaseReference!
ref = Database.database().reference()
let userRef = ref.child("user").child(uid)
var num = -1
let queue = DispatchQueue(label: "observer")
userRef.child("tilesPerRow").observe(DataEventType.value, with: { (snapshot) in
// Get user value
print("now inside the observe thing------------------")
let value = snapshot.value as? NSDictionary
num = snapshot.value as? Int ?? 0
print("just updated the number to ", num)
print("the snapshot is ", snapshot)
print("the value is ", value)
print("the real value is", snapshot.value)
print("just making sure, the number that was set is ", num)
}) { (error) in
print("there was an error!!!!!!!!!!!!!!!!!")
print(error.localizedDescription)
}
print("about to return from the function ", num)
return num
}
Currently while running this code, we get the following output.
about to return from the function -1
now inside the observe thing------------------
just updated the number to 5
the snapshot is Snap (tilesPerRow) 5
the value is nil
the real value is Optional(5)
just making sure, the number that was set is 5
Our expected output is:
now inside the observe thing------------------
just updated the number to 5
the snapshot is Snap (tilesPerRow) 5
the value is nil
the real value is Optional(5)
just making sure, the number that was set is 5
about to return from the function 5
The problem here is that we are trying to grab the value of what the query has found, but because .observe() is asynchronous, the function finishes before .observe() updates the value of num. How do we return the correct value?
You don't.
To get the asynchronous operation result you use blocks.
static func getTilesPerRow (#escaping completion: (Int?)->Void ) {
let user = Auth.auth().currentUser
guard let uid = user?.uid else {
completion(nil)
}
var ref: DatabaseReference!
ref = Database.database().reference()
let userRef = ref.child("user").child(uid)
userRef.child("tilesPerRow").observeSingleEvent(DataEventType.value, with: { (snapshot) in
// Get user value
print("now inside the observe thing------------------")
let value = snapshot.value as? NSDictionary
let num = snapshot.value as? Int ?? 0
completion(num)
}) { (error) in
print("there was an error!!!!!!!!!!!!!!!!!")
print(error.localizedDescription)
completion(nil)
}
}
When the results are ready you will get notified through the block. Upon success you get the actual num you are looking for or nil upon any error occurred.
Even you can distinguish that what sort of error occurred by adding extra parameter on your parameter list in completion block.
You also could use protocol, but thats require more knowledge like, in which class this code reside, who is the caller this sort of things. Set the protocol target to the caller, and upon completion called method will fire different protocol method based on the error or successful case occurred.
Happy coding.
My JSON looks like this:
users
username1: "WWOdh96Yr3Qs4N3GWDVq3OlQFfB2"
username2: "RJ6PztTLmsg222oUygWHtWpVHdg1"
I would like to get "username1" by their key which is (auth.uid)! and if its found i want to delete it, So after delete it will be looks like this:
users
username2: "RJ6PztTLmsg222oUygWHtWpVHdg1"
.
self.ref.child("users").queryOrderedByValue().queryEqual(toValue: user?.uid).observe(.value, with: { snapshot in
if snapshot.exists() {
print("\(snapshot.value)")
snapshot.ref.child(snapshot.value as! String).removeValue() // this deleting every thing which is WRONG!
} else{
print("Not found--")
}
self.ref.removeAllObservers()
})
}
This code deleting everything in users. I just want to delete specific user.
First of all, my approach is if I want to query 1 value at 1 moment, like you are doing, I do a observeSingleEvent (is this the best approach?). But to solve your problem, you forgot to add your "users" path. Below code is more safe to use, since you force unwrap (which is not recommend for this case):
let dataRef = self.ref.child("users")
dataRef.keepSynced(true)
if let usersUID = Auth.auth().currentUser?.uid{
dataRef.child("users").queryOrderedByValue().queryEqual(toValue: usersUID).observeSingleEvent(.value, with: { snapshot in
print(snapshot)
let values = snapshot.value as? NSDictionary
for (key, value) in values{
print(value) // does this print the uid?
print(key) // or this one?
self.ref.child("users/\(key)").removeValueWithCompletionBlock({ (err, ref) in
if err != nil {
print(err)
} else {
print(ref)
print("Removed")
}
})
}
})
}
Try to add this, right after the print(snapshot)
I'm having trouble updating a value in my Firebase database with the key status. I just can't figure out how to access the child(id) in which it is an autoID. Should I have an attribute in my Swift 3 Entity? Or is there a child(autoID) or something similar? I'm new in Firebase and Swift 3. Can any one help? This is my code:
self.ref?.child("requests").queryOrdered(byChild: "Sender").queryEqual(toValue: self.items[indexPath.row].Sender).setValue("2", forKey: "status"))
Swift 3 && Firebase 3
Hope this code will be help you...
// create the reference you want to observe
let myRequestRef = FIRDatabase.database().reference().child("requests").queryOrdered(byChild: "Sender").queryEqual(toValue: self.items[indexPath.row].Sender)
// check the sender value
myRequestRef.observeSingleEvent(of: .value, with: { (snapshot) in
//get the sender key
let senderKey = snapshot.key as String
// create status ref for new status value
let statusRef = FIRDatabase.database().reference().child("requests").child(senderKey)
// create new dict for status value
let newValue = ["Status": 2] as [String: Any]
statusRef.updateChildValues(newValue, withCompletionBlock: { (error, _) in
if error != nil {
print(error?.localizedDescription ?? "Failed to set status value")
}
print("Successfully set status value")
// Update your UI
DispatchQueue.main.async {
// Do anything with your UI
}
})
}) { (error) in
print("Failed to get snapshot", error)
}
Try moving your code inside .observe. This will allow you to get the status and check that it's accessing the right child. By using the child path below, it will override the status value but not the rest of the values inside the child.
self.ref?.child("requests").queryOrdered(byChild: "Sender").queryEqual(toValue: self.items[indexPath.row].Sender).observe(.value, with: { (snapshot) in
let value = snapshot.value as? NSDictionary
if value != nil {
print(value)
print(value["status"])
// If status is what you want, and prints out the correct status and
// correct child item
// Update the status
self.ref.child("requests/\(self.items[indexPath.row].Sender)/status").setValue("2")
}
})
I haven't tested the code above, but you should be able to make minor tweaks to get it to work in your code and on your firebase database.
You can update status value as below:
self.ref?.child("requests").queryOrdered(byChild: "Sender").queryEqual(toValue: self.items[indexPath.row].Sender).observe(.value, with: { (snapshot) in
let value = snapshot.value as? NSDictionary
if value != nil {
self.ref.child("requests/(self.items[indexPath.row].Sender)").updateChildValues(["status":"2"])
}
})
I'm trying to populate a collection view with data from a Firebase Database. I'm making following call in my viewdidload function:
ref = FIRDatabase.database().reference(withPath: "Profiles")
handle = ref.queryOrdered(byChild: title!).observe(.value, with: { snapshot in
var items: [Profiles] = []
if snapshot.value is NSNull {
print("NIL!!")
} else {
for item in snapshot.children {
let profile = Profiles(snapshot: item as! FIRDataSnapshot)
items.append(profile)
}
self.profiles = items
self.collectionView?.reloadData()
}
}) { (error) in
print(error.localizedDescription)
}
I'm getting the following error:
fatal error: unexpectedly found nil while unwrapping an Optional value
and the compiler highlights the following piece of code:
handle = ref.queryOrdered(byChild: title!).observe(.value, with: { snapshot in
I'm not understanding what the issue is, and dont understand how to fix it?!
It sounds like you're confusing the UIViewController's title member with the Firebase child you're using the query for. If you have a child named title in your data structure and want to query based on that, just replace your query statement with this:
ref.queryOrdered(byChild: "title").observe(.value, with: { snapshot in
// your code
})
The only way you'd get the error you're getting is if the variable you're using (title) has nil.
I'm facing with an error: "unexpectedly found nil while unwrapping an Optional value"
when I insert new data in coreData and reload my tableview, I recall this function
var unique = [String]()
var loadMovie = [String:[Movie]]()
func insertMovie(movie : Movie) {
let genre = movie.genre!
if unique.contains(genre) {
loadMovie[genre]!.append(movie)
} else {
unique.append(genre)
loadMovie[genre] = [movie]
}
}
and fetch data:
func fetchAndSetResults() {
let app = UIApplication.sharedApplication().delegate as! AppDelegate
let context = app.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "Movie")
do {
let movies = try context.executeFetchRequest(fetchRequest) as! [Movie]
loadMovie.removeAll()
for movie in movies {
insertMovie(movie)
}
} catch let err as NSError {
print(err.debugDescription)
}
}
and the app crushes for the error mentioned above on line: " loadMovie[genre]!.append(movie)" but if I reload app, my data are stored and visible in tableview. What's the problem?
you unwrapped optional variable means you just resolving the compile time error only. In swift you unwrapping the variable means it is represents that variable won't get the nil.You are just telling to the compiler .But now you are getting the nil (Run time Error) you need to handle this by using Optional Binding.
if let movies = try context.executeFetchRequest(fetchRequest)
{
loadMovie.removeAll()
}
Your variable loadMovie is a Dictionary with Strings as the keys and Arrays of Movies as what is stored for each key. If you are getting the error "unexpectedly found nil while unwrapping an Optional value" for line " loadMovie[genre]!.append(movie)" it means without a doubt the String called genre is sometimes not a stored as a key in your loadMovie Dictionary.
Use the code below to first make sure you can get the Array stored for that key (stored in the genre string), and if you can't then print out the String so you can debug, to find out what key is missing.
var unique = [String]()
var loadMovie = [String:[Movie]]()
func insertMovie(movie : Movie) {
let genre = movie.genre!
if unique.contains(genre) {
if let genreArray = loadMovie[genre]{
genreArray.append(movie)
} else {
NSLog("The missing genre: \(genre)")
}
} else {
unique.append(genre)
loadMovie[genre] = [movie]
}
}
Anytime you want a value that could be nil (not there) you can use the if/let pattern above. So for your second question in the comments you could replace return loadMovie[genre].count with:
if let genreArray = loadMovie[genre]{
return genreArray.count
} else {
return 0 // zero because there are no items
}
There are other ways too. You should checkout a good basic swift tutorial like: http://www.tutorialspoint.com/swift/
If you look at the section on optionals this should all be more clear. Here at stack overflow you are generally expected to first have tried to find out answers for yourself, and understand the basic theory. Unfortunately, that is why you are getting so many down votes. I hope this has helped.
If this has helped you please accept this answer by clicking on the checkmark next to it.