Json results to a string array in swift - swift

Hello i've been trying to make a json request and some of its results i want to put it to an array of string.
So i have the following code
var arrRes = [[String:AnyObject]]()
var nameaRR = [String]()
override func viewDidLoad() {
super.viewDidLoad()
Alamofire.request(.GET, "https://graph.facebook.com/search", parameters: ["q": "", "type": "place", "center": "37.928319,23.7036673", "distance": "10000","limit": "1000", "access_token": "SomeToken", "expires_in": "5184000"])
.responseJSON { (responseData) -> Void in
if((responseData.result.value) != nil) {
let swiftyJsonVar = JSON(responseData.result.value!)
//print(swiftyJsonVar)
if let resData = swiftyJsonVar["data"].arrayObject {
self.arrRes = resData as! [[String:AnyObject]]
self.nameaRR = swiftyJsonVar["data"]["name"] as! [String]
print(self.nameaRR)
}
if self.arrRes.count > 0 {
self.kati.reloadData()
}
}
}
}
The JSON Resul is the following
{
"data" : [
{
"category_list" : [
{
"id" : "272705352802676",
"name" : "Outdoors"
},
{
"id" : "115725465228008",
"name" : "Region"
}
],
"id" : "552889064768971",
"name" : "Παλαιο Φαληρο", //This String i want to put in an Array
"category" : "Local business",
"location" : {
"street" : "",
"city" : "Palaión Fáliron",
"country" : "Greece",
"longitude" : 23.6944070162,
"zip" : "17562",
"latitude" : 37.9284637008,
"state" : ""
}
}
]
}
I get a warning
Cast from 'JSON' to unrelated type '[String]' always fails
But i'm stuck of how can i put all the Strngs to the array nameaRR.
Can anyone help me find my mistake? Thanks!

look do like that
if let resData = swiftyJsonVar["data"] as? [[String:AnyObject]] {
if let categorylist = resData["category_list"] as? [[String:AnyObject]]{
if let id = categorylist["id"] as? Int{
print(id)
}
}
}

Related

how to add dictionary and get values

sorry, I'm trying to add a json of type dictionary and get the values. I don't know if I'm doing it correctly, that's how it works for me, but when I get the values ​​of the function that the dictionary returns, my application doesn't get anything.
I tried to obtain this data in different ways. I don't know if someone could give me any idea, thank you.
let jsonLifevitPBM_200 = """
{
"result" : [
{
"id_d" : 55,
"id_c" : "0",
"data" : [
{
"Diastolic" : 85,
"ErrorCode" : -1,
"Systolic" : 120,
"Pulse" : 72
}
],
"date_s" : "2021-07-28 09:45:16.201"
}
],
"error" : 0,
"flags" : 0
}
"""
let jsonKelvin = Data(jsonLifevitPBM_200.utf8)
let jsonKelvinResult = try? JSONDecoder().decode(VitalSignTermometreResponse.self, from: jsonKelvin)
let temperature = jsonKelvinResult?.result[0].data[0].Temperature
let mode = jsonKelvinResult?.result[0].data[0].Mode
let unit = jsonKelvinResult?.result[0].data[0].Unit
if let tem = temperature , let mod = mode , let uni = unit {
labelsystole.text = "Error: \(tem)"
labeldiastole.text = "Error: \(mod)"
labelPulse.text = "Error: \(uni)"
} else {
labelResult.text = "Error Medisana BU 575 Connect"
}
Another way of trying to create the dictionary and get the data was this way, but I don't think it is in the correct way
let responseDevice : [String : Any] = [
"result" : [
"id_d" : 55,
"id_c" : "0",
"data" : [
"Diastolic" : 85,
"ErrorCode" : -1,
"Systolic" : 120,
"Pulse" : 72
],
"date_s" : "2021-07-28 09:45:16.201"
]
]
if let dat = responseDevice["result"] as? [String : Any] {
if let resultData = dat["data"] as? [String : Any] {
if let diast = resultData["Diastolic"] as? String ,
let systolic = resultData["Systolic"] as? String {
println("Result : \(diast) - \(systolic)")
}
}
}
I think the best way to do that is to use a third party library to get JSON and after that you can manage JSON values.
https://github.com/SwiftyJSON/SwiftyJSON

Firebase gives sometimes only parts of my saved values and sometimes everything

I'm trying to code my own messenger. I saved the messages in Firebase database. I'm trying to access the messages with the normal way how I do it every time (database.database().reference().child("users")...., but it gives back only a few messages and only sometimes every message
I already tried it with .childAdded but it doesn't work either
func fetchMessages() {
self.messages.removeAll()
let uid = Auth.auth().currentUser!.uid
let ref = Database.database().reference().child("users").child(uid).child("chats").child(self.chatuid).child("messages")
ref.observeSingleEvent(of: .value) { (snap) in
guard let data = snap.value as? [String: AnyObject] else { return }
//MARK: data = (messageID, AnyObject)
for (messageID, _) in data {
ref.child(messageID).observeSingleEvent(of: .value) { (snap2) in
guard let data2 = snap2.value as? [String: AnyObject] else { return }
//MARK: data2 = ("message": String, "sentuid": String)
guard let message = data2["message"] as? String else { return }
guard let sentuid = data2["sentuid"] as? String else { return }
let messageToAppend = Message(sentuid: sentuid, message: message)
self.messages.append(messageToAppend)
self.messageTableView.reloadData()
}
}
}
}
//self.messages = Place where I save my fetched messages
Firebase-Structure:
{
"users" : {
"V3bLZu61KYTCG0uCWV8LH1f4rRJ3" : {
"chats" : {
"x3GzxwmyLbXrQNNyBF2a82KqrHa2" : {
"messages" : {
"20191014165454" : {
"message" : "Heyho",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165647" : {
"message" : "Blabla",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165754" : {
"message" : "Blabla",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165800" : {
"message" : "Fuchsloch",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165805" : {
"message" : "Jlksaö",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165808" : {
"message" : "Jadfsk",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165811" : {
"message" : "Jskldflsö",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014170041" : {
"message" : "JALSF",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"test" : {
"messange" : "test",
"sentUid" : "MatesForSports"
}
}
}
},
"username" : "Acc2"
},
"x3GzxwmyLbXrQNNyBF2a82KqrHa2" : {
"chats" : {
"V3bLZu61KYTCG0uCWV8LH1f4rRJ3" : {
"messages" : {
"20191014165454" : {
"message" : "Heyho",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165647" : {
"message" : "Blabla",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165754" : {
"message" : "Blabla",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165800" : {
"message" : "Fuchsloch",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165805" : {
"message" : "Jlksaö",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165808" : {
"message" : "Jadfsk",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014165811" : {
"message" : "Jskldflsö",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"20191014170041" : {
"message" : "JALSF",
"sentuid" : "V3bLZu61KYTCG0uCWV8LH1f4rRJ3"
},
"test" : {
"messange" : "test",
"sentUid" : "MatesForSports"
}
}
}
},
"username" : "Acc1"
}
}
}
I expected that the code would give back around 10 messages, but it gives sometimes 5, sometimes 3 or even only 2 messages
My firebase-structure of the messages is .child("messages"), then a unique id, then the actual message and the sender at one layer
Here's an an answer followed by a suggestion.
Let's start with replicating your structure using some hard coded values
users
uid_0
chats
chat_uid_0
messages
unique_id_0
msg: "My Message"
sent_uid: "uid_1"
unique_id_1
msg: "Hello, World"
sent_uid: "uid_3"
unique_id_2
msg: "another message"
sent_uid: "uid_2"
then the code to read in the messages, iterate over them and print out the msg and sent_uid
func readMessages() {
let usersRef = self.ref.child("users")
let messagesRef = usersRef.child("uid_0").child("chats").child("chat_uid_0").child("messages")
messagesRef.observeSingleEvent(of: .value, with: { snapshot in
let allMessages = snapshot.children.allObjects as! [DataSnapshot]
for msg in allMessages {
let msgText = msg.childSnapshot(forPath: "msg").value as? String ?? "No Msg"
let sentUid = msg.childSnapshot(forPath: "sent_uid").value as? String ?? "No sender"
print(msgText, sentUid)
}
})
}
and the output is
My message uid_1
Hello, World uid_3
another message uid_2
That being said - your structure is way to deep and should be denormalized. While it may work, as soon as you want to query for items, of find messages posted by a specific user, it just doesn't work.
I don't know your full use case but this would be a better structure
users
uid_0
name: "Hank"
uid_1
name: "Leroy"
chats
uid_0
chat_id_0: true
chat_id_1: true
uid_1
chat_id_5: true
chat_id_0
unique_id_0
msg: "My Message"
sent_uid: "uid_1"
unique_id_1
msg: "Hello, World"
sent_uid: "uid_3"
unique_id_2
msg: "another message"
sent_uid: "uid_2"
With this structure, it's all very shallow and easy to get to data - perform queries etc. You can quickly retreive all chats that uid_0 is involved with, get any messages that uid_3 ever posted or add an observer to uid_1's chat so others are notified when a chat has been added. Again, this is just an example and may not fit your case but it's something to consider.

Swift - Decoding a Deeply Nested Dictionary

I am so close - but I am struggling with a very simple function to allow me to access a data point deeply nested in my JSON. The example I am using is on the Google directions API.
Sample JSON (from GMapsAPI):
{
"geocoded_waypoints" : [
{
"geocoder_status" : "OK",
"partial_match" : true,
"place_id" : "ChIJ960bMolw44kRQcGOlOZQ-r8",
"types" : [ "premise" ]
},
{
"geocoder_status" : "OK",
"partial_match" : true,
"place_id" : "EiMxMTggU2FsZW0gU3QsIEJvc3RvbiwgTUEgMDIxMTMsIFVTQSIaEhgKFAoSCSvDfDSJcOOJEbQanF0WxROfEHY",
"types" : [ "street_address" ]
}
],
"routes" : [
{
"bounds" : {
"northeast" : {
"lat" : 42.3647252,
"lng" : -71.0555085
},
"southwest" : {
"lat" : 42.3644965,
"lng" : -71.05552419999999
}
},
"copyrights" : "Map data ©2018 Google",
"legs" : [
{
"distance" : {
"text" : "82 ft",
"value" : 25
},
"duration" : {
"text" : "1 min",
"value" : 11
},
"end_address" : "118 Salem St, Boston, MA 02113, USA",
"end_location" : {
"lat" : 42.3647252,
"lng" : -71.0555085
},
"start_address" : "115 Salem St, Boston, MA 02113, USA",
"start_location" : {
"lat" : 42.3644965,
"lng" : -71.05552419999999
},
"steps" : [
{
"distance" : {
"text" : "82 ft",
"value" : 25
},
"duration" : {
"text" : "1 min",
"value" : 11
},
"end_location" : {
"lat" : 42.3647252,
"lng" : -71.0555085
},
"html_instructions" : "Head \u003cb\u003enorth\u003c/b\u003e on \u003cb\u003eSalem St\u003c/b\u003e toward \u003cb\u003eJerusalem Pl\u003c/b\u003e",
"polyline" : {
"points" : "ciqaG~_upLO?]A"
},
"start_location" : {
"lat" : 42.3644965,
"lng" : -71.05552419999999
},
"travel_mode" : "DRIVING"
}
],
"traffic_speed_entry" : [],
"via_waypoint" : []
}
],
"overview_polyline" : {
"points" : "ciqaG~_upLm#A"
},
"summary" : "Salem St",
"warnings" : [],
"waypoint_order" : []
}
],
"status" : "OK"
}
Decodable Structure: To work with this, I am using Decodable. I have been able to access first level nested data (routes.summary), but I am struggling to get further down (for example: routes.legs.duration). My code structure is as follows:
struct Directions: Decodable {
let status: String
let routes: [Routes]
enum CodingKeys :String, CodingKey {
case status, routes
}
struct Routes: Decodable {
let summary: String
let legs: [Legs]
enum CodingKeys : String, CodingKey {
case summary, legs
}
}
struct Legs: Decodable {
let duration: Duration
enum CodingKeys : String, CodingKey {
case duration
}
}
struct Duration: Decodable {
let text: String
enum CodingKeys : String, CodingKey {
case text
}
}
Implementation after URL set-up:
URLSession.shared.dataTask(with: url) { (data, response, err) in
guard let data = data else { return }
do {
let directions = try
JSONDecoder().decode(Directions.self, from: data)
for item in directions.routes {
self.stringoutput = item.summary
}
After all this, all I want to do is be able to access "text" in the JSON and return that value. The last line in the code is able to successfully return "summary" in the JSON; and I can print(directions) and the whole array/dictionary will return in the debug area, including "text". But I still can't figure out how to do:
x = directions.routes.legs.duration.text
to make x equal to "1 min"
Would be appreciative of anyone's help.
Edit: What ended up working is Vadian's struct keys below and the following for in loop:
for item in directions.routes {
print(item.summary)
self.direct = item.summary
for items in item.legs {
self.stringoutput = items.duration.text
print(items.duration.text)
}
Cheers!
These structs don't decode all keys, but it's a starting point.
If keys and struct members have the same name you don't need to specify CodingKeys
struct Directions: Decodable {
let status: String
let routes: [Route]
}
struct Route: Decodable {
let summary: String
let legs: [Leg]
}
struct Leg: Decodable {
let duration : TextValue
let distance : TextValue
let endAddress : String
let endLocation : Location
let startAddress : String
let startLocation : Location
let steps : [Step]
}
struct TextValue: Decodable {
let text: String
let value : Int
}
struct Location: Decodable {
let lat, lng : Double
}
struct Step: Decodable {
let duration : TextValue
let distance : TextValue
let endLocation : Location
let startLocation : Location
let htmlInstructions : String
let travelMode : String
}
To decode the snake_cased keys properly you have to add the appropriate key decoding strategy
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
To access the arrays ([]) you have to get an item by index
step[0]
or iterate the array with a loop
for step in steps {}

Getting specific value of a key from child of child data in Firebase with Swift

Hello i have a datamodel like this;
{
"users" : {
"User1" : {
"flat1" : {
"flataddress" : "adres1",
"flatname" : "n1"
},
"flat2" : {
"flataddress" : "adress2",
"flatname" : "n2"
}
},
"user2" : {
"flat3" : {
"flataddress" : "a3",
"flatname" : "n1"
},
"flat4" : {
"flataddress" : "a6",
"flatname" : "a6"
}
}
}
}
Assume that user1,user2,flat1,flat2 are some IDs formed like "3DSAZDSAPOYDZ".
First question is how can i get all the flats which flataddress = "adres1"?
Second question is, if i need to retrieve all flats, there is IDs that cannot be guessed, If i do ref.getChild("users") the userIDs are retrieved from the snapshot like;
{
"users" : {
"User1" : {
"flat1" : {
"flataddress" : "adres1",
"flatname" : "n1"
},
"flat2" : {
"flataddress" : "adress2",
"flatname" : "n2"
}
},
"user2" : {
"flat3" : {
"flataddress" : "a3",
"flatname" : "n1"
},
"flat4" : {
"flataddress" : "a6",
"flatname" : "a6"
}
}
}
}
there is user ids included already, i want something like this;
{
flat1 = {
flataddress = adres1;
flatname = n1;
}
flat2 = {
flataddress = adress2;
flatname = n2;
}
flat3 = {
flataddress = a3;
flatname = n1;
}
flat4 = {
flataddress = a6;
flatname = a6;
}
}
Thanks in advance.
Let's call your main response jsonDict.If you want to get into each dictionary, you would do:
//make an empty array to put your dictionaries in
var flatsDictArray = [[String: AnyObject]]()
//first you have to unwrap each level of the dictionary response
guard let usersDict = jsonDict["users"] as? [String: AnyObject] else {
//do something here if your json response is not what you expected
//print usersDict below if you want to see what it looks like
print(usersDict)
return
}
//below we access the keys and values in the usersDict
//obj is the key, value is the value
for (obj, value) in usersDict {
if let userFlats = value as? [String: AnyObject] {
flatsDictArray.append(userFlats)
}
}
Because of the way your JSON response is structured, flatsDictArray will have two dictionaries, each dictionary will have two keys with the JSON response listed above. So they will be sorted by flats per user.
Therefore, flatsDictArray would be:
["flat1": [flataddress: adres1,
flatname: n1],
"flat2": [flataddress: adress2,
flatname: n2]],
["flat3": [flataddress: a3,
flatname: n1],
"flat4": [flataddress: a6,
flatname = a6]]
So as you see, you can step through every level of dictionary to find a key or value the way I have, so if you need to find a value that equals something, you could do it the same way.
for(obj, value) in myLovelyDictionary {
if value == "address1" {
//do something
}
}

Are there different solution how retrieve waypoints?

"-KHbCuQflKHrJiUmfpG0" : {
"waypoints" : {
"-KHbCuQflKHrJiUmfpG1" : {
"latitude" : 13.17078652595298,
"longitude" : -59.5775944578738
},
"-KHbCuQflKHrJiUmfpG2" : {
"latitude" : 13.15541190861343,
"longitude" : -59.57619643155932
},
"-KHbCuQg9W_tebl1pU66" : {
"latitude" : 13.148444967591,
"longitude" : -59.5589266947333
}
},
"subtitle" : "jamesrick",
"title" : "Highway",
"type" : "polyline"
},
I have this structure for lines in Firebase. How retrieve all data with also nested node waypoints?
ref.observeEventType(.Value, withBlock: { polylines in
if let objects = polylines.children.allObjects as? [FDataSnapshot] {
for object in objects {
polylineDictionary = object.values as? Dictionary<String, AnyObjects> {
// ? ? ?
}
}
}
})
Now I have access to title, subtitle, type but how obtain access to waypoints? When I use
`polylineDictionary["waypoints"] as? [String: [String:Double]]`
so this dictionaries are not ordered. Thanks for some advice.
This is how I would get the nested waypoints... it's basically by iterating through the keys... I would also add some error checking when grabbing the longitude and latitudes to make sure they're there, but this is the gist:
if let polylineDictionary["waypoints"] as? [String: [String:Double]] {
let waypoints = Array(polylineDictionary.keys)
for i in 0..<waypoints.count {
let waypointId = waypoints[i]
let latitude = polylineDictionary[waypointId]["latitude"]
let longitutde = polylineDictionary[waypointId]["longitude"]
}
}
It's not clear from the question about ordering; if you just want to get to the waypoints, it's pretty straight forward:
Assume your complete Firebase structure is:
root_node
"-KHbCuQflKHrJiUmfpG0" : {
"waypoints" : {
"-KHbCuQflKHrJiUmfpG1" : {
"latitude" : 13.17078652595298,
"longitude" : -59.5775944578738
},
"-KHbCuQflKHrJiUmfpG2" : {
"latitude" : 13.15541190861343,
"longitude" : -59.57619643155932
},
"-KHbCuQg9W_tebl1pU66" : {
"latitude" : 13.148444967591,
"longitude" : -59.5589266947333
}
},
"subtitle" : "jamesrick",
"title" : "Highway",
"type" : "polyline"
}
Suppose I want the data for this specific node, -KHbCuQflKHrJiUmfpG0
let nodeRef = rootRef.childByAppendingPath("-KHbCuQflKHrJiUmfpG0")
nodeRef.observeSingleEventOfType(.Value , withBlock: { snapshot in
print(snapshot.value) //prints everything in the node
let title = snapshot.value["title"] as! String //to get any element
print(title) //prints Highway
var waypoints = [String: [String:String]]() //dict to hold key:value, unordered
waypoints = snapshot.value["waypoints"] as! Dictionary
print(waypoints) //prints the 3 waypoints and their children (as a dict)
//get fancy and convert the dictionary to an array (which can be sorted)
let arr = waypoints.map {"\($0) \($1)"}
for point in arr {
print(point)
}
}