Issue displaying array of image from url - ios

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.

Related

iOS Swift iterate over an Array of Dictionary Items from Firestore

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 {
}

Mapping from array of dictionaries to array of numbers in Swift

Here is a function that should turn an an array of key-value pairs for orders NSArray containing Dictionary<String, Any> to an array of IDs for each order ([NSNumber]).
However, I am still having problem with the type conversion, the error:
Type 'Any' has no subscript members
How to perform the mapping cleanly in Swift?
#objc static func ordersLoaded(notification:Notification) -> [NSNumber] {
// Function receives a Notification object from Objective C
let userInfo:Dictionary = notification.userInfo as! Dictionary<String, Any>
// orders is an array of key-value pairs for each order Dictionary<String,Any>
let ordersWithKeyValuePairs:NSArray = userInfo["orders"] as! NSArray // Here a typed array of Dictionaries would be preferred
// it needs to be simplified to an array of IDs for each order (NSNumber)
// orderID is one of the keys
let orderIDs:[NSNumber];
orderIDs = ordersWithKeyValuePairs.flatMap({$0["orderID"] as? NSNumber}) // Line with the error
/*
orderIDs = ordersWithKeyValuePairs.map({
(key,value) in
if key==["orderID"] {
return value
} else {
return nil
}
}) as! [NSNumber]
*/
return orderIDs
}
You can try this
if let ordersWithKeyValuePairs = userInfo["orders"] as? [[String:Any]] {
let result = ordersWithKeyValuePairs.compactMap{$0["orderID"] as? Int }
}
Here is what worked, casting ordersWithKeyValuePairs to [Dictionary<String, Any>] solved the problem to me:
#objc static func ordersLoaded(notification:Notification) -> [NSNumber] {
// Function receives a Notification object from Objective C
let userInfo:Dictionary = notification.userInfo as! Dictionary<String, Any>
// orders is an array of key-value pairs for each order Dictionary<String,Any>
let ordersWithKeyValuePairs:[Dictionary<String, Any>] = userInfo["orders"] as! [Dictionary<String, Any>]
// it needs to be simplified to an array of IDs for each order (NSNumber)
// orderID is one of the keys
let orderIDs:[NSNumber];
orderIDs = ordersWithKeyValuePairs.flatMap({$0["orderID"] as? NSNumber}) // Line with the error
return orderIDs
}

Sorting Firebase Realtime Database data in Swift

I need to show these data in a table view, but they have been on the table view in mixing order. How can I put them in the same order as in the database. Please help, I will deeply appreciated.
First image shows my iPhone screen after running the project, second one is the database. I want them exact order as in the database.
I hope periods objects look like this:
struct PeriodItem {
let key: String
let periodEnd: String
let periodName: String
let periodStart: String
let ref: FIRDatabaseReference?
init(periodEnd: String, periodName: String, periodStart: String, key: String = "") {
self.key = key
self.periodEnd = periodEnd
self.periodName = periodName
self.periodStart = periodStart
self.ref = nil
}
init(snapshot: FIRDataSnapshot) {
key = snapshot.key
let snapshotValue = snapshot.value as! [String: AnyObject]
periodEnd = snapshotValue["periodEnd"] as! String
periodName = snapshotValue["periodName"] as! String
periodStart = snapshotValue["periodStart"] as! String
ref = snapshot.ref
}
func toAnyObject() -> Any {
return [
"periodEnd": periodEnd,
"periodName": periodName,
"periodStart": periodStart,
"key": key
]
}
}
So
When you fill your array of Periods fully, just use sorting:
// periods - array of objects from firebase database
let yourTableViewPeriodsArray = periods.sorted(by: { $0.key < $1.key }) // maybe ">" instead of "<"
Then:
DispatchQueue.main.async {
self.tableView.reloadData()
}
Hope it helps.

How to add custom class array into multidimensional array swift 3

I had firebase database structure like this:
Currently I'm fetching the top key which is categories, But I want it to make dynamic when network call when selecting picker based on its categories and display on tableview, Is there any way to do that in swift3? But somehow I figure out by adding it in array.
my question is how do I convert array to multidimensional array?
func getCategories() {
DataService.ds.REF_CATEGORIES.observe(FIRDataEventType.value, with: { snapshot in
if let snapshot = snapshot.children.allObjects as? [FIRDataSnapshot] {
for (_, item) in snapshot.enumerated().reversed() {
let key = item.key.capitalized
self.categories.append(key)
print("key --> \(key)")
if let catDict = item.value as? JSONDictionary {
let count = catDict.count
for i in catDict {
if let finalCat = i.value as? JSONDictionary {
let finalKey = i.key
let category = Pizza(categoriesKey: finalKey , categoriesData: finalCat)
self.multiCat.append([category])
print("multiCat --> \(self.multiCat)")
print("i count --> \(count)")
}
}
}
}
}
})
}
Console Log: multiCat --> [[Pizza,Pizza,Pizza,Pizza,Pizza,Pizza,Pizza,Pizza,Pizza,]]
What I want is: [[Pizza,Pizza,Pizza], [Pizza,Pizza,Pizza], [Pizza,Pizza,Pizza,]]

Flatened Firebase query in iOS issues

I have a "flatened" Firebase structure and trying to retrieve a dictionary of values from a "secondary" database member. In other words, I have a conversation which has a "to" cell which has the key to a business listing. With this key, I'm trying to retrieve the business listing and its children (url, description, title). For some reason, I can print the snapshot2.value and it responds with the expected value, but I can't pass it to my class initialization.
DataService.ds.REF_CONVOS.observeEventType(.Value, withBlock: {snapshot in
self.convoListings.removeAll()
self.convoListings = []
//Data parsing from Firebase. The goal is to breakdown the data received and store in a local model.
if let snapshots = snapshot.children.allObjects as? [FDataSnapshot] {
for snap in snapshots {
for convo in userConvos {
// Going into the children of the main object for the conversations.
//print("\(snap)")
if convo == snap.key {
//print(snap.value)
print(snap.value)
if let businessDict = snap.value as? Dictionary<String, AnyObject> {
businessName.removeAll()
let test = businessDict["to"] as? String
DataService.ds.REF_BusinessListing.childByAppendingPath(test).childByAppendingPath("title/").observeSingleEventOfType(.Value, withBlock: { snapshot2 in
print(snapshot2.value)
})
let key = snap.key
let post = ConvoListing(convoKey: key, dictionary: businessDict, businessName: self.test2)
self.convoListings.append(post)
}
}
}
}
}
self.tableView.reloadData()
})
Your nesting seems of:
DataService.ds.REF_BusinessListing.childByAppendingPath(test).childByAppendingPath("title/").observeSingleEventOfType(.Value, withBlock: { snapshot2 in
print(snapshot2.value)
})
let key = snap.key
let post = ConvoListing(convoKey: key, dictionary: businessDict, businessName: self.test2)
self.convoListings.append(post)
Keep in mind the observeSingleEventOfType loads the data asynchronously. For this reason, if you have code that needs the value that you loaded, you need to put that code in the block:
DataService.ds.REF_BusinessListing.childByAppendingPath(test).childByAppendingPath("title/").observeSingleEventOfType(.Value, withBlock: { snapshot2 in
print(snapshot2.value)
let key = snap.key
let post = ConvoListing(convoKey: key, dictionary: businessDict, businessName: self.test2)
self.convoListings.append(post)
})

Resources