Accessing Array outside of the loop [duplicate] - arrays

This question already has an answer here:
Assign value of a Firestore document to a variable
(1 answer)
Closed 2 years ago.
I have an Array where some different UserID's are stored.
Each UserID is connected with their corresponding data in Firestore.
So now I want to fetch all the JSON Data from the UserID's and make them accessible to decode them later.
Therefore the fetched Data (coming as a Dictionary) from each user must be accessible separately.
I tried it with that way:
var fetchedIDs = ["ID1", "ID2", "ID3"]
var finalArray = [[String: Any]]()
for id in fetchedIDs{
let docRef = Firestore.firestore().collection("Data").document(id)
docRef.getDocument { (document, error) in
if let document = document, document.exists {
let myDict: [String: Any] = document.data() as! [String: Any]
finalArray.append(myDict)
}
}
}
}
But the problem is that the finalArray (like finalArray[0]) is just accessible in the For-Loop.
It should be accessible outside of the loop and look like that:
finalArray[0] should have the Dictionary data from ID1
finalArray[1] should have the Dictionary data from ID2
Maybe I am thinking to complicated for that..
Can someone help me out ?
Is there generally a good source for learning about scopes and how the data should be accessed like in that scenario?
Thanks!

Finally get it working with the following code:
var fetchedIDs = ["ID1", "ID2", "ID3"]
func loadData(com:#escaping( ([[String: Any]]) -> ())){
var myArray = [[String: Any]]()
for id in fetchedIDs{
let refLike = db.collection("Data").document(id)
refLike.getDocument { (document, error) in
if let err = error {
print("Error getting documents: \(err)")
} else {
let myDict: [String: Any] = document?.data() as! [String: Any]
myArray.append(myDict)
}
com(myArray)
}
}
}
loadData(){ arr in
if (arr.count == fetchedIDs.count){
print ("User 1 has the following data: \(arr[0])")
print ("User 2 has the following data: \(arr[1])")
}
}

Related

Firestore - appending data to a single value inside a struct

How can I update a single value inside of a struct. Currently I'm fetching all of the data inside multiple documents of a collection with the below function. the data structure is as follows:
People - collection
DocumentID
Name: "Joe"
Friends (Object)
1 (Object)
Name: "Sally"
2 (Object)
Name: "Sam"
DocumentID
Name: "Emily"
Friends (Object)
1 (Object)
Name: "Peter".
If I run the below code it jut creates a new array, whereas I would like to merge the two together. Any help is greatly appreciated. Many thanks!!
func loadData() {
let userRef = db.collection("Users").document(user!)
let docRef = userRef.collection("People")
docRef.getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
if let snapshot = querySnapshot {
for document in snapshot.documents {
let data = document.data()
let name = data["name"] as? String ?? ""
let newPeople = People(name: name, friends: [:])
self.peopleArray.append(newPeople)
if let friends = data["Friends"] as? [String: Any] {
for (key, _) in friends {
let number = friends[key] as? [String: Any] ?? [:]
let friendsName = number["name"] as? String ?? ""
\\ The code in which I want to update the value of friendsName into the previous set array
let newFriends = People(name: name, friendsName: friendsName)
self.peopleArray.append(newFriends)
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
}
}
}
What I would like the array to look like:
[ name: Joe, friends: ["name": Sally, "name": Sam]], [name: Emily, friends: [name: Peter]]
Updated Code
var friendsName: [String: [String: Int]] = [:]
var friendsArray = [String: Int]()
func loadData() {
let userRef = db.collection("Users").document(user!)
let docRef = userRef.collection("People")
docRef.getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
if let snapshot = querySnapshot {
for document in snapshot.documents {
let data = document.data()
let name = data["name"] as? String ?? ""
if let friends = data["Friends"] as? [String: Any] {
for friend in friends {
let key = friend.key
let values = friend.value
let friendsDict = friends[key] as? [String: Any] ?? [:]
let friendsNameString = friendsDict["name"] as? String ?? ""
self.friendsArray.updateValue(friendsNameString, forKey: key)
}
self.friendsName.updateValue(self.friendsArray, forKey: "name")
let newPeople = People(name: name, friends: self.friendsName)
self.peopleArray.append(newPeople)
self.friendsArray.removeAll()
self.friendsName.removeAll()
}
}
}
}
}
}
The way you are doing it seems a little too complex to what you require. Firestore has quite fast queries so you can have different collections for people and friends.
Lets say for example that in your "people" collection you have the names of all the users and other properties that you may need... Email, age, gender, etc etc.
Then in a second collection you can add the relations for each user. For example, "Friends" contains documents with fields friendA: AAA, FriendB: BBB. Then you won't have any duplicates in your data.
The way you are doing it creates too many duplicated that you don't need. For example, in your Joe document you have set that Sally is a friend. But then in your Sally document you will have to set that Joe is a friend. This makes the database more difficult to maintain and with a lot of duplicates.
If you make two different collections for People and Friends the code for fetching also becomes simpler.

why are my items not going into the array? Xcode and swift NSURLSession

I am using Swift and Xcode, I have built model object with the following variables:
var itemImageNames: [String]?
var itemTitle: String?
var itemDescription: String?
var itemURL: String?
In the mainviewcontroller, I created an variable of model type. I am initiating a NSURLSession...dataTaskWithURL... and adding itemImageNames that I receive back from the server by using append. The data comes back as valid, I've parsed it and it is indeed coming back as Strings. I've tried two solutions,
create a string array out of the images and set that array to self.item.itemImageNames?
do {
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? [[String: AnyObject]] {
var imageURLs: [String] = [""]
for dictionary in json {
if let imageURL = dictionary["url"] as? String {
imageURLs.append(imageURL)
print(imageURL)
}
}
self.featuredItem.itemImageNames? = imageURLs
append each of the strings as I get them using self.item.itemImageNames?.append(image)
do {
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? [[String: AnyObject]] {
for dictionary in json {
if let imageURL = dictionary["url"] as? String {
self.featuredItem.itemImageNames?.append(imageURL)
print(imageURL)
}
}
For some reason, the itemImageNames remains nil, using both approaches. I am sure it will work if I just use one image (e.g. the 1st image), and change itemImageNames to a "String?".
In addition, I can update the itemTitle, itemDescription, and itemURL easily by just setting them to self.item.itemTitle, self.item.itemDescription, self.item.itemURL, respectively. Is there something I'm missing on how to enter information into an array?
In approach #2 initialize the itemImageNames array before trying to append to it. If you try to append to an array that is nil then nothing will happen.
itemImageNames = []
for dictionary in json {
if let imageURL = dictionary["url"] as? String {
self.featuredItem.itemImageNames?.append(imageURL)
print(imageURL)
}
}

How we can find an element from [AnyObject] type array in swift

I have [AnyObject] array
var updatedPos = [AnyObject]()
I am setting data in that according to my requirement like!
let para:NSMutableDictionary = NSMutableDictionary()
para.setValue(posId, forKey: "id")
para.setValue(posName, forKey: "job")
let jsonData = try! NSJSONSerialization.dataWithJSONObject(para, options: NSJSONWritingOptions())
let jsonString = NSString(data: jsonData, encoding: NSUTF8StringEncoding) as! String
self.updatedPos.append(jsonString)
Now in my code i have some requirement to remove the object from this array where id getting matched according to requirement Here is the code which i am trying to implement
for var i = 0; i < updatedPos.count; i++
{
let posItem = updatedPos[i]
print("Id=\(posItem)")
let pId = posItem["id"] as? String
print("secRId=\(pId)")
if removeId! == pId!
{
updatedPos.removeAtIndex(i)
}
}
Here print("Id=\(posItem)") give me output asId={"id":"51","job":"Programmer"} but here i am not able to access id from this object. here print("secRId=\(pId)") give me nil
First of all use native Swift collection types.
Second of all use types as specific as possible.
For example your [AnyObject] array can be also declared as an array of dictionaries [[String:AnyObject]]
var updatedPos = [[String:AnyObject]]()
Now create the dictionaries and add them to the array (in your example the dictionary is actually [String:String] but I keep the AnyObject values).
let para1 : [String:AnyObject] = ["id" : "51", "job" : "Programmer"]
let para2 : [String:AnyObject] = ["id" : "12", "job" : "Designer"]
updatedPos.append(para1)
updatedPos.append(para2)
If you want to remove an item by id use the filter function
let removeId = "12"
updatedPos = updatedPos.filter { $0["id"] as? String != removeId }
or alternatively
if let indexToDelete = updatedPos.indexOf{ $0["id"] as? String == removeId} {
updatedPos.removeAtIndex(indexToDelete)
}
The JSON serialization is not needed for the code you provided.
PS: Never write valueForKey: and setValue:forKey: unless you know exactly what it's doing.
After some little bit stuffs I have found the very easy and best solution for my question. And I want to do special thanks to #vadian. Because he teach me new thing here. Hey Thank you very much #vadian
Finally the answer is I had covert posItem in json Format for finding the id from Id={"id":"51","job":"Programmer"} this string
And the way is
let data = posItem.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: false)
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)
if let dict = json as? [String: AnyObject] {
let id = dict["id"]
if removeId! == id! as! String
{
updatedLoc.removeAtIndex(i)
}
}
}
catch {
print(error)
}

Parsing JSON into swift predefined array

I am trying to get items from an api (JSON) and to parse it into a predefined swift array. I have searched and looked for hours but due to my lack of skills I wasn't able to find anything suitable my case.
My predefined array looks like this:
init?(participants: String, photoguest: UIImage?, photohome: UIImage?, time: String, stadium: String, channel: String)
the JSON structure is like this(entire json file):
{"gameId":"255","gameWeek":"17","gameDate":"2016-01-03","awayTeam":"SEA","homeTeam":"ARI","gameTimeET":"4:25 PM","tvStation":"FOX","winner":"SEA"}
My current code looks like this (Games is the class where I connect variables from array with table cell items):
var gameplan = [Games]()
func loadNFLgames(){
let apiURL = NSURL(string: "http://www.fantasyfootballnerd.com/service/schedule/json/test/")
let data: AnyObject? = NSData(contentsOfURL: apiURL!)
let homeTeam = (data as! NSDictionary)["homeTeam"] as! String
let awayTeam = (data as! NSDictionary)["awayTeam"] as! String
let gameDate = (data as! NSDictionary)["gameDate"] as! String
let gameTimeET = (data as! NSDictionary)["gameTimeET"] as! String
let tvStation = (data as! NSDictionary)["tvStation"] as! String
/*
for schleife mit API daten:
for gameWeek = currentWeek{ //every game where gameWeek matches currentWeek
*/
// create variables from api calls
let api_guest = awayTeam
let api_home = homeTeam
let api_tvhost = tvStation
let api_time = gameDate + ", " + gameTimeET + " ET" // convert gameDate to day e.g. SUN
let api_stadion = "N/A"
// prepare data for array
let gamedata = Games(participants: api_guest+" # "+api_home, photoguest: UIImage(named: api_guest), photohome: UIImage(named: api_home), time: api_time, stadium: api_stadion, channel: api_tvhost)!
// add data to array
gameplan.append(gamedata)
}
I am getting the following error:
Could not cast value of type '_NSInlineData' (0x1a0cfd428) to
'NSDictionary' (0x1a0cf3380).
EDIT: The error is being thrown here:
let homeTeam = (data as! NSDictionary)["homeTeam"] as! String
Your help is highly appreciated.
Thanks in advance!
hello your data variable doesn't contain the Json you r looking for. so you have to serialize it to json like alexander suggested but NSJSONSerialization can throw an error so we have tu put in in try
so your code will be something like this (i suggest always using dispatch_async to make it in background thread than use the completion closure to get your result)-->
func loadNFLgames(completionClosure: (result : [Games]) ->()){
let queue: dispatch_queue_t = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
dispatch_async(queue, {
let URL = "http://www.fantasyfootballnerd.com/service/schedule/json/test/"
print(URL)
if let data = NSData(contentsOfURL: NSURL(string: URL)!){
if let JsonObject = try? NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as! NSMutableDictionary{
print(JsonObject)
//here you can loop through the JsonObject to get the data you are looking for
//when you get your array of Games just pass it the the completion closure like this
completionClosure(result: gameplan)
}
}
})
}
PS: please let me know if you need more help.
Your data variable is NSData type (not NSDictionary). You have to convert it in order to use it. Try something like that:
let decodedJson = NSJSONSerialization.JSONObjectWithData(data, options: nil) as! NSDictionary
And than you can use it like standard dictionary
let homeTeam = decodedJson["homeTeam"] as! String

Swift: Looping through a Dictionary Array

I'm struggling to loop through an array of dictionary values returned from a web service call.
I've implemented the following code and I seem to be encountering a crash on running.
I'd also like to store the results into a custom Struct. Really having difficulty achieving this and the answers on here so far haven't worked. Would be grateful if someone is able to help.
let nudgesURLString = "http://www.whatthefoot.co.uk/NUDGE/nudges.php"
let nudgesURL = NSURL(string: nudgesURLString)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(nudgesURL!, completionHandler: {data, response, error -> Void in
if error != nil {
println(error)
} else {
let nudgesJSONResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
let nudges: NSDictionary = nudgesJSONResult["nudges"] as NSDictionary
if let list = nudgesJSONResult["nudges"] as? [[String:String]] {
for nudgeDict in list {
let location = nudgeDict["location"]
println(location)
}
}
}
})
task.resume()
}
NOTICE
This answer was written using Swift 1.2 and as such, there may be some slight stylistic and syntax changes required for the answer to work depending on your current Swift system.
Answer -- Swift 1.2
This line is crashing your code:
let nudges: NSDictionary = nudgesJSONResult["nudges"] as NSDictionary
You're forcing a cast that Swift can't handle. You never make it to your for-loop.
Try changing your code to look more like this:
let nudgesURLString = "http://www.whatthefoot.co.uk/NUDGE/nudges.php"
let nudgesURL = NSURL(string: nudgesURLString)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(nudgesURL!, completionHandler: {data, response, error -> Void in
if error != nil {
println(error)
} else {
let nudgesJSONResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as [String : AnyObject]
if let nudges = nudgesJSONResult["nudges"] as? [[String : String]] {
for nudge in nudges {
let location = nudge["location"]
println("Got location: \(location)")
println("Got full nudge: \(nudge)")
}
}
}
})
task.resume()
Thanks,
I created the following Struct which stored the data, and also lets me create dictionaries in the view controller for a particular index.
struct NudgesLibrary {
var location: NSArray?
var message: NSArray?
var priority: NSArray?
var date: NSArray?
var nudges: NSArray?
init(nudgesObject: AnyObject) {
nudges = (nudgesObject["nudges"] as NSArray)
if let nudges = nudgesObject["nudges"] as? NSArray {
location = (nudges.valueForKey("location") as NSArray)
message = (nudges.valueForKey("message") as NSArray)
priority = (nudges.valueForKey("priority") as NSArray)
date = (nudges.valueForKey("date") as NSArray)
}
}
}

Resources