iOS Swift iterate over an Array of Dictionary Items from Firestore - ios

I am trying to iterate over the following dictionary:
Dictionary in Firebase
This is my code:
Global.sharedInstance.db.collection("usuarios").getDocuments { (snapshot, error) in
if error != nil {
print("error de lectura usuarios...")
} else {
if let snapshot = snapshot {
for document in snapshot.documents {
let data = document.data()
let txtIdentificador = data["identificador"] as? String ?? ""
let txtBio = data["bio"] as? String ?? ""
let txtNombre = data["nombre_usuario"] as? String ?? ""
let txtFotoPerfil = data["foto_perfil"] as? String ?? ""
var arrFotos = data["fotos"] as? [String: [String:String]]
}
}
}
}
I am able to retrieve the first few lines, like the id, the biography, name, etc.
But when I try to access the array of dictionary I have no idea.
This is the main idea:
I have a set of users, which I iterate over with the first loop 'for document in documents...", then each user has a set of photos. I want to iterate over the 3 photos, and in each iteration I want to retrieve the fields, so I can create a object called Image and associate the user with the 'hasUpload(Image)'.
I would like to know how to iterate over X photos an in each iteration retrieve the fields.
Something like this:
var arrFotos = data["fotos"] as? [String: [String:String]]
for foto in arrFotos {
for (key,value) in foto {
}
}
I get the error: For-in loop requires '[String : [String : String]]?' to conform to 'Sequence'; did you mean to unwrap optional?

A similar StackOverflow case can be found here and this is how they resolved it:
You can either do this, where x is the index and token is the element:
for (x, token) in transcriptCandidate.enumerated() {
}
Or this if you don't need the index:
for token in transcriptCandidate {
}

Related

Swift Firebase Save/Update multiple parents with the same child values

I have an array of strings which is the "uid's" of users. I am trying to append data/children to these multiple "uid's". Adding children or updating children to individual parents/users is easy and I understand how to do it. The problem is that this array can either contain 1 uid or 50 uid's. Is it possible for me to take these uid's and then update them with the same value? I am unsure what code to provide since I am just trying everything to attack this.
With the code below, this is me send a message to other users.
Array of uid strings
var data = [String]()
Sample code of me sending a message to 2 users, just wanted to provide something here to show I know how to update/save data
private func sendMessageWithProperties(_ properties: [String: Any]) {
let businessRef = Database.database().reference().child("Business Group Chats Messages").child((group?.uid)!).child((Auth.auth().currentUser?.uid)!)
let ref = Database.database().reference().child("Business Group Chats Messages").child((Auth.auth().currentUser?.uid)!).child((group?.businessName)!)
let businesChildRef = businessRef.childByAutoId()
let childRef = ref.childByAutoId()
let fromID = Auth.auth().currentUser!.uid
let timeStamp = Int(Date().timeIntervalSince1970)
var value:[String: Any] = ["fromId" : fromID, "timeStamp" : timeStamp, "name": self.loggedInUserData?["name"] as? String]
properties.forEach { (k,v) in
value[k] = v
}
childRef.updateChildValues(value) { (err, ref) in
if err != nil {
print(err!)
return
}
Database.database().reference().child("Business Group Chats").child((self.group?.uid)!).child((Auth.auth().currentUser?.uid)!).updateChildValues(["last message" : childRef.key!, "timestamp" : timeStamp, "businessName":(self.group?.businessName)!])
Database.database().reference().child("Business Group Chats").child((Auth.auth().currentUser?.uid)!).child((self.group?.uid)!).updateChildValues(["last message" : childRef.key!, "timestamp" : timeStamp])
self.inputContainerView.inputTextField.text = nil
}
}
Here is me taking that array of "uid's" and then pulling and printing that I can access each "uid" through a array of strings. Allowing me to access, now I can append data to each.
Database.database().reference().child("Businesses").observe(.value, with: { snapshot in
if snapshot.exists() {
self.businessUID = snapshot.value as? NSDictionary
if let dict = snapshot.value as? NSDictionary {
for item in dict {
let json = JSON(item.value)
let businessUid = json["uid"].stringValue
for uid in self.data {
if uid == businessUid {
//print(uid)
self.businessessuids = uid
print(self.businessessuids)
Database.database().reference().child("Businesses").child(self.businessessuids).observe(.value, with: { snapshot in
print(snapshot)
print("Trying to pull data from multiple strings right here this shoudld work")
})
print("printing the values to match with the string UID's")
}
}
}
}
} else {
print("does not exist")
}
})

Cannot subscript a value of type '[[String : Any]]' with an index of type 'String'

I'm trying to extract the info from a json array and i'm getting this error
"Cannot subscript a value of type '[[String : Any]]' with an index of type 'String'"
here
if let rev = place.details?["reviews"] as? [[String:Any]] {
if let ver = rev["author_name"] as? String { // <- IN THIS LINE I GET THE ERROR
}
}
i know that if i cast the type as [String : Any] instead of [[String:Any]] it will work, but in this case i have to cast it as an array of arrays otherwise it doesn't read the json, so how can i solve the problem?
[[String:Any]] is an array. It can be only subscripted by Int index.
You have to iterate over the array for example:
if let reviews = place.details?["reviews"] as? [[String:Any]] {
for review in reviews {
if let authorName = review["author_name"] as? String {
// do something with authorName
}
}
}
You can't access an item in an array with a String. You have to use Int
[[String:Any]] This is an array of dictionaries.
[[String:Any]] is a two dimensional Array. It can be only subscripted using Int index.
It is better to use a forEach loop, e.g.
if let reviews = place.details?["reviews"] as? [[String:Any]] {
reviews?.forEach { review in
if let authorName = review["author_name"] as? String {
// do something with authorName
}
}
}
I think you are mixing up dictionaries and arrays here.
If you want to access an element in an array, you have to use an Int index like this
let a = ["test", "some", "more"] // your array
let b = a[0] // print(b) = "test"
If you want to access an element in a dictionary, you can access it via its key, in your case a String
let dict: [String: Any] = ["aKey": "someValue"]
let value = dict["aKey"] // print(value) = "someValue"
In your case you have an array of dictionaries, each of them containing information about a review. If you want to access the author of one of your reviews, you have to first get the review dictionary out of your array like this:
if let reviews = place.details?["reviews"] as? [[String:Any]],
let review = reviews[0] {
// here you can access the author of the review then:
if let author = review["author_name"] as? String {
// do something
}
}
Instead of accessing just the first review like in my example, you can also loop via the array to access all of the reviews one by one

Swift 3 retrieve value from nested JSON Array

Hi I am currently learning Swift 3, and I have an app I am "developing" to provide weather for a specific location.
I have got my MetOffice API and retrieved the JSON required. I am able to retrieve the location without issue, but when I try to get the temp data I get no result. The temp data is listed as DM in the JSON and is an array within an array within a dictionary within dictionary.
my current code looks like
if let SiteRep = dict["SiteRep"] as? Dictionary<String, Any> {
if let DV = SiteRep["DV"] as? Dictionary<String,Any> {
if let location = DV["Location"] as? Dictionary<String, Any> {
if let period = location["Period"] as? Dictionary<String, Any> {
if let Rep = period["Rep"] as? [Dictionary<String, Any>] {
if let DM = Rep[0]["DM"] as? Double {
self._currentTemp = DM
} } } } } }
relevant vars are declared above this.
I'm not sure how to correct this code to pull this required value back from the JSON
Json as follows, the value i am trying to retrieve is highlighted in bold
{
"SiteRep":{
"Wx":{ },
"DV":{
"dataDate":"2017-02-10T12:00:00Z",
"type":"Forecast",
"Location":{
"i":"350497",
"lat":"99.6115",
"lon":"-21.0017",
"name":"TOWN",
"country":"ENGLAND",
"continent":"EUROPE",
"elevation":"160.0",
"Period":[
{
"type":"Day",
"value":"2017-02-10Z",
"Rep":[
{
"D":"NE",
"Gn":"16",
"Hn":"77",
"PPd":"51",
"S":"9",
"V":"GO",
**"Dm":"2",**
"FDm":"-2",
"W":"24",
"U":"1",
"$":"Day"
},
{
"D":"NNW",
"Gm":"20",
"Hm":"89",
"PPn":"58",
"S":"11",
"V":"GO",
"Nm":"-1",
"FNm":"-6",
"W":"24",
"$":"Night"
}

Issue displaying array of image from url

Through Firebase I'm calling many url to convert it to UIImage but aren't displayed in a corrected order. The print func stamp to the consolle the current index:
0 2 1 3 4
The JSON is like:
{
"evento_1" = "http://.altervista.org/evento1.jpeg";
"evento_2" = "http://.altervista.org/evento2.jpeg";
"evento_3" = "http://.altervista.org/evento3.jpeg";
"evento_4" = "http://.altervista.org/evento4.jpeg";
"evento_5" = "http://.altervista.org/evento5.jpeg";
}
Function to get the data:
ref.observeEventType(.Value, withBlock: { snapshot in
let nsDictionary = snapshot.value as? NSDictionary
for (key, value) in nsDictionary! {
dict[key as! String] = value
}
var index = 0
for (_, url ) in dict {
self.loadImage(url as! String, i: index)
index++
}
}, withCancelBlock: { error in
print(error.description)
})
Image Loader func:
func loadImage(urlString:String,i:Int)
{
let url = NSURL(string: urlString)
let data = NSData(contentsOfURL: url!)
self.eventi[i].image = UIImage(data: data!)
}
Put your Firebase snapshot keys into an array and the key:value pairs into a dictionary. Then sort the key array:
arrayOfKeys = Array(dict.keys) //swift
arrayOfKeys.sort {
return $0 < $1
}
then you can iterate over the array to get the event name (the key), which corresponds to the objects in your dictionary (access it by key) which returns it's value.
or (and I like this better)
Just take every .value dictionary and put each into an array then sort the array by the eventName (assuming that's the key)
eventArray.sort({ $0.eventName > $1.eventName })
As Jay and Eric mention: dictionaries have no defined order. The FDataSnapshot does have a defined order, but once you convert it to a dictionary, you're throwing that away.
So instead of first converting to a dictionary and then looping, you should simply loop over the children of the snapshot with:
for child in snapshot.children {
let key = child.key as String
print(key);
}
Where I print the key, you can do whatever you need with the child snapshot.

Array keeps returning nil even when values are stored Swift Firebase

Hi I am new to Swift and Firebase here and I am trying to append the objects I get into the array I have created. But when I return the array, it returns nil even when I print the array it shows the values are stored inside.I tried to assign it to another array but it still returns nil. Please help me as I am currently a newbie to Swift and Firebase and need some guidance. Thanks in advance.
func retrieveData() -> Array<AnyObject>{
var ref = Firebase(url: "my_firebase_url")
ref.queryOrderedByChild("datetime").observeEventType(.Value, withBlock: {
snapshot in
if let i = snapshot.value as? NSDictionary {
for item in i {
if let value = item.value as? NSDictionary {
self.adArray.append(value)
println(self.adArray[0])
println(self.adArray.count)
self.codeNum = value["code"] as! String
self.datetime = value["datetime"] as! String
self.nameEvent = value["name"] as! String
println("code is \(self.codeNum) and name is \(self.nameEvent) at \(self.datetime)")
}
}
}
})
println(adArray.count)
return adArray }

Resources