I am currently getting an error on my app when I am performing a segue to another view which is performed by clicking on an Image View.
The error says: fatal error: unexpectedly found nil while unwrapping an optional value. I am not sure why this is happening but below is an image where the error is occuring. I am assuming there is something wrong with the segue because the error occurs when clicking the button. However the error is highlighted on this piece of code which is confusing me?
This is the code:
func loadComments() {
let postCommentRef = FIRDatabase.database().reference().child("post-comments").child(self.postId)
postCommentRef.observe(.childAdded, with: {
snapshot in
print("observe key")
print(snapshot.key)
FIRDatabase.database().reference().child("comments").child(snapshot.key).observeSingleEvent(of: .value, with: {
snapshotComment in
if let dict = snapshot.value as? [String: Any] {
//Retrieving from the database - post Model created class
let newComment = Comment.transformComment(dict: dict)
self.getUser(uid: newComment.uid!, completed: {
self.comments.append(newComment)
self.tableView.reloadData()
})
}
})
})
}
Related
This is my relevant struct:
struct MealPlan {
var docID:String?
var title:String?
var ingredientsProduce:[String]?
var ingredientsProtein:[String]?
var ingredientsSpices:[String]?
var ingredientsOther:[String]?
var isStarred:Bool?
}
And this is my model:
class MealPlanModel {
var delegate:MealPlanProtocol?
var listener:ListenerRegistration?
func getMealPlans(_ starredOnly:Bool = false) {
// Detach any listener
listener?.remove()
// Get a reference to the database
let db = Firestore.firestore()
var query:Query = db.collection("mealPlans")
// If filtering for starred Meal Plans, update the query
if starredOnly {
query = query.whereField("isStarred", isEqualTo: true)
}
self.listener = query.addSnapshotListener({ (snapshot, error) in
// Check for errors
if error == nil && snapshot != nil {
var mealPlans = [MealPlan]()
// Parse documents into mealPlans
for doc in snapshot!.documents {
let m = MealPlan(docID: doc["docID"] as! String, title: doc["title"] as! String, ingredientsProduce: doc["ingredientsProduce"] as! [String], ingredientsProtein: doc["ingredientsProtein"] as! [String], ingredientsSpices: doc["ingredientsSpices"] as! [String], ingredientsOther: doc["ingredientsOther"] as! [String], isStarred: doc["isStarred"] as! Bool)
mealPlans.append(m)
}
// Call the delegate and pass back the notes in the main thread
DispatchQueue.main.async {
self.delegate?.mealPlansRetrieved(mealPlans: mealPlans)
}
}
})
This is what I can't figure out:
My project was building fine with this code
Then I added a new document in Firestore with the same keys
App started crashing
I deleted that document from Firestore (so going back to where I was at (1) when it worked) and the project continued to crash
The error I'm getting is: Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value. The error is marked at ingredientsProduce: doc["ingredientsProduce"] as! [String] from my code above.
I couldn't find any typos and the keys all have values in Firestore. Also, everything was working fine before I added/deleted the new document, so it seems like nothing has changed since it last worked. I cleared my build folder and quit/reopened Xcode as well.
Anyone know what might be happening?
Well you are force unwrapping an optional value hence your app is crashing when it turns out to be nil.
doc["ingredientsProduce"] as! [String] // as! means force cast it to array of strings in your example
If the value of ingredientsProduce is an optional you can't force unwrap it and expect it not to crash when it's nil.
Example of safe unwrapping
if let myValues = doc["ingredientsProduce"] as? [String] {
// safe to use myValues
_ = myValues.map { print($0) }
}
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.
I'm using this function to check to see if a certain handle exists in my database. It works fine for the most part - if the handle exists, it updates the table view to display that user. However if there is no match for the handle entered, my alert view is not showing up.
// Search DB for matching handles
#IBAction func searchHandleButtonPressed(_ sender: Any) {
if let handleToSearch = handleSearchTextField.text?.lowercased() {
let databaseRef = FIRDatabase.database().reference()
databaseRef.child("users").queryOrdered(byChild: "lowercaseHandle").queryEqual(toValue: handleToSearch).observeSingleEvent(of: .value, with: { (snapshot) in
if let snapDict = snapshot.value as? [String:AnyObject] {
for each in snapDict{
let key = each.key
let handle = each.value["handle"] as! String
self.returnedHandles.removeAll()
self.returnedHandles.append(handle)
let pic = each.value["profilePicture"] as! String
self.returnedUsersProfilePic = pic
self.returnedUsersUID = key
if handle.lowercased() != handleToSearch {
self.noHandleFoundAlert()
}
if handle != "" {
DispatchQueue.main.async {
self.getFriendsInfo()
self.tableView.reloadData()
}
}
}
}
}, withCancel: {(Err) in
// print(Err.localizedDescription)
})
}
}
I put the alert in the loop as:
if handle.lowercased() != handleToSearch {
self.noHandleFoundAlert()
}
But obviously this isn't the correct approach as it isn't working. If I enter a random string of characters, or a handle that I know isn't in use, the alert doesn't come up. Where else would I put the alert so it will show up if there's no match?
The snapshot will be converted to an empty dictionary with your current code.
Before converting the snapshot.value to a Dictionary, check if it exists with snapshot.exists(): https://firebase.google.com/docs/reference/ios/firebasedatabase/api/reference/Classes/FIRDataSnapshot#-exists
You first have to check if the query you made, has data. So you have a
.hasChild("handle")
it returns a boolean, so when is true you do the loop, else notified user.
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.