Fetching images from Firebase child - firebase

everyone. I have troubles with fetching a chunk of images from a child in my Firebase database. I am doing an iOS project and using swift 3 and XCode. Basically, after all, my "image" variable returns "nil" Please, help me if you can. Here is the code I am using:
let ref = FIRDatabase.database().reference().child("menu")
ref.observeSingleEvent(of: .value, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let image = dictionary["foodImageUrl"] as? String
print(image as Any) // this returns nil
and an example of a database structure
I need to fetch all the "foodImageUrl" from all children from the menu node

your snapshot.value is the list of sub items from menu, not the details info of each node, so you have to use forEach, and then inside each node, use dictionary["foodImageUrl"] as? String to get your image
try this
let ref = FIRDatabase.database().reference().child("menu")
ref.observeSingleEvent(of: .value, with: { (snapshot) in
for rest in snapshot.children.allObjects as! [FIRDataSnapshot] {
if let dictionary = rest.value as? [String: AnyObject]{
let image = dictionary["foodImageUrl"] as? String
print(image as Any)
}
}

Related

Cannot reach to members of an array with index

I am trying to fill an array with data from Firebase. But after filling the array I can't call its' members from their index. I am filling the array by this function
func loadSounds(){
Firestore.firestore().collection("data").getDocuments{ (snapshot, error) in
if error == nil{
for document in snapshot!.documents{
let name = document.data()["name"] as? String ?? "error"
let sounds = document.data()["sounds"] as? [String : [String : Any]]
var soundsArray = [dataSound]()
if let sounds = sounds{
for sound in sounds {
let soundName = sound.value["name"] as? String ?? "error"
let soundImage = sound.value["image"] as? String ?? "error"
soundsArray.append(dataSound(name: soundName , image: soundImage ))
}
}
categoriesArray.append(Category(category: name , sounds: soundsArray))
}
print(categoriesArray[0].category)
} else {
print(error)
}
} }
When I try to access it from View, It gives index out of bounds error.
struct ContentView: View {
init(){
loadSounds()
}
var body: some View {
Text(categoriesArray[0].category)}}
If I try to access it via ForEach, it works, also when I try to print it from loadSounds function it works, but I need to access them from their index in View. Thanks for any help.
Never access items of an array by index in the rendering area of a SwiftUI View, in almost all cases the array is empty when the view is rendered the first time.
In your case use .first and handle the optional
var body: some View {
Text(categoriesArray.first?.category ?? "No value")}} // or empty string

how to write auth based Firestore Rules for specific collections

I have a collection called Orders and I have two other collections for Users & Drivers. I want the Orders collection to be accessible only by the UID's that inside the Drivers collection.
All the people signed into the app are users, but Drivers are the only users that can access the Orders documents.
The logic is to check if the user is signed and the Drivers collection contains a field that has the UID of that user. If the collection field contains the UID of that user, then he can access that collection of document.
allow write, read: if isSignIn() & `Driver colletion contains that user UID`
How can I do that and if I can I need some help write that code?
Here are my rules and I did not change that much in it. All that I know is this code is for every document in my database, so I need to write some specifics
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow write, read: if isSignIn();
}
function isSignIn(){
return request.auth != null;
}
}
}
here is how I'm getting the data from Firestore
func newOrders(){
let fireStore = Firestore.firestore()
let doc = fireStore.collection("Orders")
self.driverListener = doc.addSnapshotListener { (query, err) in
if err != nil {
print(err?.localizedDescription ?? "")
}
guard let querysnap = query else {return}
querysnap.documentChanges.forEach({ change in
if change.type == .added {
self.DriverOffers = []
for document in querysnap.documents{
let snap = document.data()
guard let orderLoc = snap["orderLocation"] as? GeoPoint else {return}
guard let docId = snap["docId"] as? String else {return}
guard let name = snap["name"] as? String else {return}
guard let phone = snap["phone"] as? String else {return}
guard let time = snap["time"] as? String else {return}
guard let marketName = snap["marketName"] as? String else {return}
guard let price = snap["amount"] as? String else {return}
guard let userImg = snap["userImg"] as? String else {return}
guard let storeImg = snap["storeImg"] as? String else {return}
guard let order = snap["order"] as? String else {return}
guard let userid = snap["userUid"] as? String else {return}
guard let timestamp = snap["date"] as? Timestamp else {return}
let date = Date(timeIntervalSince1970: TimeInterval(timestamp.seconds))
guard let userlocation = snap["userLocation"] as? GeoPoint else {return}
let offer = driverOrdersData(docId: docId, userUid: userid, name: name, phone: phone, amount: price, time: time, marketName: marketName, storeimgUrl: storeImg, userImgUrl: userImg, date: date, orderDetails: order, orderLocation: orderLoc, userLocation: userlocation, distance1: distance1, distance2: distance2 )
self.DriverOffers.append(offer)
DispatchQueue.main.async {
self.DriverOrdersTV.reloadData()
}
}
}
}
})
}
}
You cannot check in security rules whether a document exists with a specific value in it, as that would require your rules to query the collection and would be costly and not scale.
The trick to implement this use-case (and many others) is to use the UID of a user for the document ID in the Drivers (and probably also Users) collection. You can do this by adding those documents with something like
let uid = ....; // wherever you get the UID from
firebase.firestore().collection("Drivers").doc(uid).set({ uid: uid });
Now with that structure in place, you can check whether a document with the specific UID exists in your security rules, which is possible:
function isDriver() {
return exists(/databases/$(database)/documents/Drivers/$(request.auth.uid))
}
Also see the Firebase documentation on accessing other documents in security rules.

fetch and retrieve data from firebase in swift

what I am trying to do is fetching data from firebase, but the data is nil because the user did not send his data to firebase yet, so when he enter the view controller that should show his data, the compiler make error. How can I solve this error? I tride to add alert, but it's still not working.
func getData(){
ref = Database.database().reference()
let userID = Auth.auth().currentUser?.uid
ref.child("users")
.queryOrdered(byChild: "uid")
.queryEqual(toValue:userID)
.observe(.value) { (snapshot, error) in
if error == nil{// alert} elses{
if let data = snapshot.value as? NSDictionary {
if snapshot.exists() {
for a in ((snapshot.value as AnyObject).allKeys)!{
let users = data.value(forKey:a as! String) as! NSDictionary
let address = users.value(forKey:"Address") as! NSDictionary
self.lblAddressNickname.text = address.value(forKey:"addressNickname") as? String
}
}
}
}
}
}
So as of now i understand the question that you have problem in fetching data from firebase when no data is in the firebase and then alert will come and it will redirect to a new controller?
So based on my understanding i will give answer if any problem of understanding things then reply me?
first you have to check that particular user have any data in firebase database so if there is no data then alert function will call
if let data == data
{
fetch_logic is here
}
else
{
let alert = UIAlertController(title:"Add Data",message:"",preferredStyle: .alert)
let action = UIAlertAction(title: "Add Button", style: .default) { (UIAlertAction) in
}
alert.addAction(action)
present(alert,animation:true,completion:true)
}

Could not cast value of type '__NSDictionaryM' (0x1111152b0) to 'FIRDataSnapshot' Firebase Swift 3

I am trying to read nested data structures from Firebase Database, but I don't know how to manage the case when an object of type [String:AnyObject] could be nil.
When readFeesCleaner(callback_) is called, it throws an error.
func readFeesCleaner(callback: #escaping ((_ feesCleaner: FeesCleaner) -> Void)) {
dbRef.child("FeesCleaner").child(self.uidOfTextField!).observeSingleEvent(of: .value, with: { (snapshot: FIRDataSnapshot) in
guard !(snapshot.value is NSNull) else {
return
}
//throws error: signal SIGABRTCould not cast value of type '__NSDictionaryM' (0x1111152b0) to 'FIRDataSnapshot' (0x10ef16d18).
let feesCleanersReceived = FeesCleaner(snapshot: (snapshot.value)! as! FIRDataSnapshot)
callback(feesCleanersReceived)
}) { (error:Error) in
print(#line, "\(error.localizedDescription)")
}
}
struct FeesCleaner {
var outstandingFees: AnyObject!
var timeStampFeesSaved: [String:AnyObject]!
var backgroundCheck: AnyObject!
init(
outstandingFees: AnyObject? = nil, //value might not exist when reading
timeStampFeesSaved: [String:AnyObject]? = nil,// value might not exist when reading
backgroundCheck: AnyObject) {
self.outstandingFees = outstandingFees
self.timeStampFeesSaved = timeStampFeesSaved
self.backgroundCheck = backgroundCheck
}//end of init
//read data here
[full struct data here][1]
https://gist.github.com/bibscy/dc48f7107459379e045a50fdbbc35335
}//end of struct
There's a number of issues here. First:
how to manage the case when an object of type [String:AnyObject]
could be nil.
You've handled that with the prior statement, noting that you can also add
if snapshot.exists == false {return}
Second: You've got to handle optionals properly - if a var could be nil, you need code in place to handle that situation and not plow through it. If you force unwrap an optional you are essentially stating that for sure, it will never be nil, so basically, don't do that.
One fix could be to simply pass the snapshot as a DataSnapshot and then pull out the properties one at a time; if they exist, assign them, if not set to 0 or nil or some other placeholder.
Something like this inside the Firebase closure:
let feesCleanersReceived = FeesCleaner(withSnapshot: snapshot)
and then your struct like this: note we are leveraging the nil coalescing operator, ??
struct FeesCleanerStruct {
var outstandingFees: String?
var timeStampFeesSaved: String?
init(withSnapshot: DataSnapshot) {
let dict = withSnapshot.value as! [String: Any]
self.outstandingFees = dict["outstandingFees"] as? String ?? "0.0"
self.timeStampFeesSaved = dict["timeStampFeesSaved"] as? String ?? "0"
}
}

Iteration through dictionaries, Firebase snapshot using

I am having a problem while iterating through a dictionary. First check my database
And here is my code
ref.child("Events").observe(.value, with: { (snapshot) in
for child in snapshot.children{
let snap = child as! DataSnapshot
let valueSnap = snap.value as? [[String:Any]]
let nombreEventDansClub = valueSnap?.count
print(valueSnap)
for index in 0...nombreEventDansClub!-1
{
print(valueSnap![index]["name"])
//print(valueSnap![index]["end_time"])
if(valueSnap![index]["end_time"] as? String == nil)
{
//do Something
}
else{
let end_time_test = valueSnap![index]["end_time"] as? String
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
dateFormatter.timeZone = TimeZone(abbreviation: "GMT+2:00")
let end_test = dateFormatter.date(from: end_time_test!)!
The recuperation is perfect but for example : if Event-0-(3) didn't exist the app would crash, I know the problem is that I calculate the number of events in a : Event-(something) and iterate according to this. I was wondering if there is a smarter way. Thanks in advance
You can parse the snapshot this way:-
ref.child("Events").observe(.value, with: { (snapshot) in
guard let values = snapshot as? [Any] else { return }
for value in values {
guard let childrens = value as? [Any] else { continue }
for children in childrens {
guard let dict = children as? [String: Any] else { continue }
for key in dict.allkeys {
// TO debug all keys and values
print(dict[key])
}
print(dict["description"] as? String)
print(dict["end_time"] as? String)
print(dict["id"] as? String)
// other keys
}
}
}
Force unwrapping may cause your app crash unexpectedly.

Resources