Retrieving Data From Firebase in JSON - Swift - json

I am trying to retrieve information from Firebase. I can get the snapshot in JSON but I am having trouble accessing it and saving the values in my app.
This is how the code looks like:
self.ref.child("users").child(userFound.userRef!).child("currentGame").observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot)
if let snapDict = snapshot.value as? [String:AnyObject] {
for each in snapDict {
self.theApp.currentGameIDKey = String(each.key)
self.currentGame.playerAddressCoordinates?.latitude = each.value["playerLatitude"] as! Double
print(self.theApp.playerAddressCoordinates?.latitude)
print(self.currentGame.currentGameIDKey)
}
}
})
And this is how it prints in the console:
Snap (currentGame) {
"-KUZBVvbtVhJk9EeQAiL" = {
date = "2016-10-20 18:24:08 -0400";
playerAdress = "47 Calle Tacuba Mexico City DF 06010";
playerLatitude = "19.4354257";
playerLongitude = "-99.1365724";
};
}
The currentGameIDKey gets saved but the self.currentGame.playerAddressCoordinates do not.

Assuming that you have multiple objects in your node "currentGame" and you're looking to extract the player address coordinates and current game id key from all of them, here's how you can do it :
self.ref.child("users").child(userFound.userRef!).child("currentGame").observeSingleEvent(of: .value, with: { (snapshot) in
if(snapshot.exists()) {
let enumerator = snapshot.children
while let listObject = enumerator.nextObject() as? FIRDataSnapshot {
self.theApp.currentGameIDKey = listObject.key
let object = listObject.value as! [String: AnyObject]
self.currentGame.playerAddressCoordinates?.latitude = object["playerLatitude"] as! Double
print(self.theApp.playerAddressCoordinates?.latitude)
print(self.currentGame.currentGameIDKey)
}
}
According to your database design, you were not accessing the "playerLatitude" in the correct manner. "playerLatitude" is a child of the child of your snapshot.
I'm guessing you are inserting into "currentGame" using childByAutoId(). Therefore, you need to unwrap it one level further to access it.
Also, if you have to access only one child, you can also use :
self.ref.child("users").child(userFound.userRef!).child("currentGame").observeSingleEvent(of: .value, with: { (snapshot) in
if(snapshot.exists()) {
let currentGameSnapshot = snapshot.children.allObjects[0] as! FIRDataSnapshot
self.theApp.currentGameIDKey = currentGameSnapshot.key
self.currentGame.playerAddressCoordinates?.latitude = currentGameSnapshot.childSnapshot(forPath: "playerLatitude").value as! Double
print(self.theApp.playerAddressCoordinates?.latitude)
print(self.currentGame.currentGameIDKey)
}
Hope this helps!

Related

Store JSON into array

I need to store each part of the json into a data structure, maybe Array?
This is what I have when I call Firebase realtime:
ref.observeSingleEvent(of: .value, with: { (snapshot) in
for child in snapshot.children {
let snap = child as! DataSnapshot
let key = snap.key
let value = snap.value
print("######################################################\n\n")
print("key = \(key) value = \(value!)")
}
})
when printed it looks like this:
What would be the best way to accomplish this?
I need to store the title, description and postUrl
EDIT:
If I do this:
let userID = Auth.auth().currentUser?.uid
ref.child("post").child(userID!).observeSingleEvent(of: .value, with: { (snapshot) in
// Get user value
print(snapshot)
}) { (error) in
print(error.localizedDescription)
}
that would give me the snapshot id but not the values because the user is not in that DB, how can I print the snapshots without saying current user?
If you can't for some reason access the snapshot's value parameter as above, you will probably need to manually parse the value string (as it's not proper json). The code below will allow you to initialise the data structure with the value text. This assumes value is a nicely formed string as in the example below. If not you may need to play with it a bit more:
let valueString = """
{
description = dawdled
postUrl = http://darrengillman.com
timestamp = 1572735278831
title = testy
}
"""
struct DataStruct {
let decription: String
let postUrl: URL
let timestamp: Int
let test: String
init?(from value: String) {
let strings = Array(value.components(separatedBy: .newlines).dropLast().dropFirst()).map{$0.components(separatedBy: "=")}.map{$0.dropFirst().first!.trimmingCharacters(in: .whitespaces)}
guard strings.count == 4 else {return nil}
self.decription = strings[0]
self.postUrl = URL(string: strings[1])!
self.timestamp = Int(strings[2]) ?? 0
self.test = strings[3]
}
}
let myData = DataStruct(from: valueString)

Get JSON Element in Swift 3

Please excuse me if this is a simple question, but I am stuck. I have tried to read everything I can to work it out myself.
I am trying to extract a URL from JSON data, I get the JSON data fine and I can print it to the console, however I can't work out how to access the URL for the audio file.
This is the code I use to get the JSON:
let session = URLSession.shared
_ = session.dataTask(with: request, completionHandler: { data, response, error in
if let response = response,
let data = data,
let jsonData = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) {
if let dictionary = jsonData as? [String: Any] {
if let prounce = dictionary["pronunciations"] as? [String: Any]{
if let audioPath = prounce["audioFile"] as? String {
print(audioPath)
}
}
}
print(response)
print(jsonData)
} else {
print(error)
print(NSString.init(data: data!, encoding: String.Encoding.utf8.rawValue))
}
}).resume()
The output I get is:
metadata = {
provider = "Oxford University Press";
};
results = (
{
id = maladroit;
language = en;
lexicalEntries = (
{
entries = (
{
etymologies = (
"late 17th century: French"
);
grammaticalFeatures = (
{
text = Positive;
type = Degree;
}
);
senses = (
{
definitions = (
"inefficient or inept; clumsy:"
);
examples = (
{
text = "both men are unhappy about the maladroit way the matter has been handled";
}
);
id = "m_en_gb0494140.001";
}
);
}
);
language = en;
lexicalCategory = Adjective;
pronunciations = (
{
audioFile = "http://audio.oxforddictionaries.com/en/mp3/maladroit_gb_1.mp3";
dialects = (
"British English"
);
phoneticNotation = IPA;
phoneticSpelling = "\U02ccmal\U0259\U02c8dr\U0254\U026at";
}
);
text = maladroit;
}
);
type = headword;
word = maladroit;
}
);
}
I want to get the URL called audioFile in the pronunciations. Any help is much appreciated.
If my guess is right, your output shown above lacks opening brace { at the top of the output.
(I'm also assuming the output is taken from your print(jsonData).)
Your jsonData is a Dictionary containing two values:
A dictionary value for "metadata"
An array value for "results"
So, you cannot retrieve a value for "pronunciations" directly from jsonData (or dictionary).
You may need to:
Retrieve the value for "results" from jsonData, it's an Array
Choose one element from the "results", it's a Dictionary
Retrieve the value for "lexicalEntries" from the result, it's an Array
Choose one element from the "lexicalEntries", it's a Dictionary
Retrieve the value for "pronunciations" from the lexicalEntry, it's an Array
Choose one element from the "pronunciations", it's a Dictionary
Here, you can access the values in each pronunciation Dictionary. In code, you need to do something like this:
if
let dictionary = jsonData as? [String: Any],
let results = dictionary["results"] as? [[String: Any]],
//You need to choose one from "results"
!results.isEmpty, case let result = results[0],
let lexicalEntries = result["lexicalEntries"] as? [[String: Any]],
//You need to choose one from "lexicalEntries"
!lexicalEntries.isEmpty, case let lexicalEntry = lexicalEntries[0],
let pronunciations = lexicalEntry["pronunciations"] as? [[String: Any]],
//You need to choose one from "lexicalEntries"
!pronunciations.isEmpty, case let pronunciation = pronunciations[0]
{
//Here you can use `pronunciation` as a Dictionary containing "audioFile" and some others...
if let audioPath = pronunciation["audioFile"] as? String {
print(audioPath)
}
}
(You can use let result = results.first instead of !results.isEmpty, case let result = results[0], if you always use the first element for arrays. Other two lines starting from !...isEmpty, case let... as well.)
You need to dig into the target element from the outermost element step by step.

Swift unable to pull information from other Swift files unless in #IBAction

I'm currently working with the latest version of Swift. In a nutshell, I'm pulling information from a webpage and storing said information into an array. Here is how I did that (forgive the indenting..):
class TransactionData {
var transactions: [Transaction] = []
init() {
getTransactionData()
}
func getTransactionData() {
let jsonUrl = "php file with json"
let session = NSURLSession.sharedSession()
let shotsUrl = NSURL(string: jsonUrl)
let task = session.dataTaskWithURL(shotsUrl!) {
(data, response, error) -> Void in
do {
let jsonData: NSArray = (try NSJSONSerialization.JSONObjectWithData(data!, options:NSJSONReadingOptions.MutableContainers) as? NSArray)!
for var index = 0; index < jsonData.count; ++index {
let orderID: String = jsonData[index]["orderID"] as! String
let orderDate: String = jsonData[index]["orderDate"] as! String
let orderType: String = jsonData[index]["orderType"] as! String
let paymentType: String = jsonData[index]["paymentType"] as! String
let itemName: String = jsonData[index]["itemName"] as! String
let itemPrice: String = jsonData[index]["itemPrice"] as! String
let itemTaxes: String = jsonData[index]["itemTaxes"] as! String
let orderModifications: String = jsonData[index]["orderModifications"] as! String
let orderVariations: String = jsonData[index]["orderVariations"] as! String
let transaction = Transaction(orderID: orderID, orderDate: orderDate, orderType: orderType, paymentType: paymentType, itemName: itemName, itemPrice: itemPrice, itemTaxes: itemTaxes, orderModifications: orderModifications, orderVariations: orderVariations)
self.transactions.append(transaction)
}
} catch _ {
// Error
}
}
task.resume()
}
When I want to call the information, I use this:
let transactionData = TransactionData()
for transaction in transactionData.transactions {
print("\(transaction)")
}
The only time information gets pulled through to a ViewController is when I'm using an IBAction. If I try anywhere else, it doesn't read the information through. For example, I'm trying to pull information from the online website to pass into a TableViewController. It just won't pull the information.
Any ideas?
You need to establish a connection between your ViewControllers so they can pass data between them. One common way is through a delegate protocol that is set during a segue between screens. Here is a tutorial on it.
To expand on this a little bit, it sounds like you have a class Transactions that is called by your ViewController to load data. If you then try to access a new instance of that in your TableViewController, you don't have the data, because a new instance is being created. There are two ways to avoid this issue:
Pass data (or a reference to your Transactions) from VC -> TVC via delegate.
Use a singleton pattern for your data model so that all can access it.
To avoid concurrency issue, I would suggest doing the former.

JSON with Swift 2, Array Structure

I'm Having trouble with JSON and Swift 2.
I'm getting this Array from the server
[{"KidName":"Jacob","KidId":1,"GardenID":0},
{"KidName":"Sarah","KidId":2,"GardenID":0},
{"KidName":"Odel","KidId":3,"GardenID":0}]
I'm familiar with JSON and I know it's not the recommended way to get a JSON, since it's supposed to be something like
{"someArray":[{"KidName":"Jacob","KidId":1,"gardenID":0}, .....
So my first question is it possible to run over the first JSON I've post and get the KidName number without editing the JSON and Add to it a JSON OBJECT to hold the array ?
my second question is really with Swift 2, how can I get the KidName (after I've edited the JSON to have an holder for the array)?
this is my code... (please read the Notes I've added)
BTW, I'm familiar with SwiftyJSON as well...
// Method I've build to get the JSON from Server, the Data is the JSON
sendGetRequest { (response, data ) -> Void in
// need to convert data to String So I can add it an holder
if let str = NSString(data: data, encoding: NSUTF8StringEncoding) as? String {
/**
after editing the str, i'm Having a valid JSON, let's call it fixedJSON
*/
let fixedJSON = "{\"kidsArray\":\(dropLast)}"
// Now I'm converting it to data back again
let jsonTodata = fixedJSON.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
// After Having the data, I need to convert it to JSON Format
do{
let dataToJson = try NSJSONSerialization.JSONObjectWithData(jsonTodata, options: []) as! [String:AnyObject]
//Here I'm getting the KidID
if let kidID = jsonSe["kidsArray"]![0]["KidId"]!!.integerValue {
print("kidID in first index is: \(kidID)\n")
}
//NOW trying to get the KidName which not working
if let kidname = jsonSe["kidsArray"]![0]["KidName"]!!.stringValue {
print("KidName is \(kidname)\n")
}
}
So as you can see, I'm not able to get the KidName.
Any Help Would be Appreciate.
You can use the following function to get the 'someArray' array and then use this getStringFromJSON function to get the 'KidName' value.
func getArrayFromJSON(data: NSDictionary, key: String) -> NSArray {
if let info = data[key] as? NSArray {
return info
}
else {
return []
}
}
let someArray = self.getArrayFromJSON(YourJSONArray as! NSDictionary, key: "someArray")
func getStringFromJSON(data: NSDictionary, key: String) -> String {
if let info = data[key] as? String {
return info
}
return ""
}
let KidName = self.getStringFromJSON(someArray as! NSDictionary, key: "KidName")
Hope this might be useful to you.

Cannot properly parse JSON Data because of its format?

I am trying to parse data which look:
It looks like each record is sequential.. 0, 1, 2 and then within each record there are lots of key value pairs such as the name or showID.
I want to go into each record and only get certain pairs, for example the name, showID and Date.
Here is my code, I am unsure what should be my modal in for item in loop
in other words, how do I get the specific fields into my empty dictionary array?
let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) -> Void in
if let urlContent = data
{
do
{
var jsonResult:NSDictionary = try NSJSONSerialization.JSONObjectWithData(urlContent, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
if let items = jsonResult["items"] as! NSArray?
{
var emptyArrayOfDictionary = [[String : AnyObject]]()
for item in 0...jsonResult.count
{
}
}
The idea would be to create a struct (or a class) which contains the properties you need, created with an initializer from the values in your dictionaries.
Let's say you want to make "Show" objects containing the show name and the show ID.
You could create a struct like this:
struct Show {
let name:String
let showID:Int
init?(dictionary: [String:AnyObject]) {
guard let name = dictionary["name"] as? String,
let showID = dictionary["showID"] as? Int else {
return nil
}
self.name = name
self.showID = showID
}
}
Then iterate over your dictionaries and pass each one to the struct initializer, something like this:
let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) -> Void in
if let urlContent = data {
do {
if let jsonResult = try NSJSONSerialization.JSONObjectWithData(urlContent, options: []) as? [String : AnyObject] {
if let items = jsonResult["items"] as? [[String : AnyObject]] {
let shows = items.flatMap { Show(dictionary: $0) }
}
}
} catch {
print(error)
}
}
}
The struct initializer is an Optional one, meaning that if the dictionary does not contain the keys "name" or "showID" it will not create the object and will return nil instead; that's why we're using flatMap to iterate instead of map (because flatMap unwraps the Optionals).
Now you have an array of objects, shows, and you can filter or sort its contents easily with Swift methods like sort, filter, etc.
Each object in the shows array is a Show object and has name and showID properties with the data of your dictionaries.
What flatMap does is create an array of Show objects by iterating (like a loop) over the initial array. On this line:
let shows = items.flatMap { Show(dictionary: $0) }
the $0 represents the current array element. What it means is that for each element in the items array, we take it and create a new Show instance with it, and put the resulting array of objects in the constant shows.
There's also map which is often used, but here the init of our Show struct is an optional init, so it returns an Optional Show, and flatMap knows how to deal with this (it will safely unwrap the optional and ignore the nil ones) where map does not.
If you would like to simplify your son parsing try this Open source https://github.com/SwiftyJSON/SwiftyJSON
With this you access name field of item 0
let userName = json[0]["name"].string