json parsing in swift - ios

Here is my Json
{
"id": "63",
"name": "Magnet",
"price": "₹1250",
"description": "",
"image": [
"catalog/IMG-20150119-WA0012_azw1e3ge.jpg",
"catalog/IMG-20150119-WA0029_6mr3ndda.jpg",
"catalog/IMG-20150119-WA0028_ooc2ea52.jpg",
"catalog/IMG-20150119-WA0026_4wjz5882.jpg",
"catalog/IMG-20150119-WA0024_e38xvczi.jpg",
"catalog/IMG-20150119-WA0020_vyzhfkvf.jpg",
"catalog/IMG-20150119-WA0018_u686bmde.jpg",
"catalog/IMG-20150119-WA0016_c8ffp19i.jpg"
],
"thumb_image": [
"cache/catalog/IMG-20150119-WA0012_azw1e3ge-300x412.jpg",
"cache/catalog/IMG-20150119-WA0029_6mr3ndda-300x412.jpg",
"cache/catalog/IMG-20150119-WA0028_ooc2ea52-300x412.jpg",
"cache/catalog/IMG-20150119-WA0026_4wjz5882-300x412.jpg",
"cache/catalog/IMG-20150119-WA0024_e38xvczi-300x412.jpg",
"cache/catalog/IMG-20150119-WA0020_vyzhfkvf-300x412.jpg",
"cache/catalog/IMG-20150119-WA0018_u686bmde-300x412.jpg",
"cache/catalog/IMG-20150119-WA0016_c8ffp19i-300x412.jpg"
],
"specifications": [
{
"Fabrics": [
"Pure chiffon straight cut suits 48" length"
]
},
{
"MOQ": [
"Minimum 10"
]
}
]
}
In above json string the "specification" arraylist has dynamic number of key and each key has dynamic number of values
So how can parse this? Please help if anyone knows this...
Thanks in advance

There are multiple ways to do parsing. In your case specifications should be an array, so you'll be able to loop on each items.
You might want to :
Create your own JSON parse class / methods ;
Use an existing library to parse JSON.
For the second option, you can give a look at the following :
https://github.com/Wolg/awesome-swift#jsonxml-manipulation

var yourJson = data as? NSDictionary
if let id = yourJson.valueForKey("id") as String
{
//save your id from json
}
if let name = yourJson.valueForKey("name") as String
{
//save your name
}
...
if let images = yourJson.valueForKey("image") as NSArray
{
for im in images
{
//save image
}
//the same for all othe images
}
... And so on...
You should also watch some tutorials, to understand the basics of JSON parsing..
https://www.youtube.com/watch?v=MtcscjMxxq4

Related

Configuring collectionView:cellForRowAt based on an array of strings

I've got this JSON data (not verbatim) that I get from the backend. It contains the actual data and an array of strings describing the sequence of cells to be shown:
{
"data": [
{
"name": "text",
"data": {
"text": "some text"
}
},
{
"name": "pic",
"data": {
"url": "https://somepic.jpg",
"text": "picture"
}
},
{
"name": "switcher",
"data": {
"id": 1,
"options": [
{
"id": 0,
"text": "option 1"
},
{
"id": 1,
"text": "option 2"
},
{
"id": 2,
"text": "option 3"
}
]
}
}
],
"view": [
"text",
"pic",
"switcher",
"text"
]
}
The problem is that I can't get my head around how to configure cellForRowAt: and get the right order of cells in one section. (i.e. text, pic, selector, text).
I tried a couple of things:
Looping through "view" array and switching on each individual view string to dequeue a specific cell but that doesn't seem to work since returning a cell from a switch case gives a "unexpected non-void return value in void function" error.
I was also thinking about turning a "view" array into a dictionary and then, based on keys in it, dequeue a specific cell but then again, a dictionary should have unique keys meaning that I will not have 2 "text" entries, one of them will be lost.
So, the questions is: how can I dequeue specific cells based on the array of strings? It's also important to understand that it should be done in one section. I'm feeling that it's somehow not that difficult to implement but I'm kinda lost right now. Thanks!
you need to transform your view list and data array into an array of cell contents that you can use inside the TableViewDelegate and TableViewSource method :
var cellsContents : [Int] = []
for aView in view {
var found = false
var index = 0
for aData in data {
if !found {
if let name = aData["name"] as? String {
if aView == name {
found = true
cellsContents.append(index)
continue
}
}
index = index + 1
}
}
}
Then :
number of rows : cellsContents.count
type and contents for a row : data[cellsContents[indexPath.row]]["name"] and data[cellsContents[indexPath.row]]["data"]

Decode KeyValuePairs<String: Person> from JSON

I have a JSON response that looks something like this:
{
"persons": {
"John": {
"name": "John",
"age": 24
},
"Michael": {
"name": "Michael",
"age": 44
},
"Jack": {
"name": "Jack",
"age": 25
}
}
}
As you can see this could be parse with a struct that looks like this:
struct PersonsResponse: Decodable {
let persons: [String: Person]
}
struct Person: Decodable {
let name: String
let age: Ing
}
However, what this does, is returns a dictionary and parses fine. What I would need is to preserve the order of the persons as they arrive inside this JSON response. I have come across KeyValuePairs in swift which basically are ordered dictionaries but for the love of God I can't figure out how to decode it into being an KeyValuePairs<String, Person>.
Apple documentation says that instantiating a KeyValuePairs object is as easy as doing:
let recordTimes: KeyValuePairs = ["Florence Griffith-Joyner": 10.49,
"Evelyn Ashford": 10.76,
"Evelyn Ashford": 10.79,
"Marlies Gohr": 10.81]
Literally. But when I am decoding my response with:
struct PersonsResponse: Decodable {
let persons: KeyValuePairs<String, Person>
...
...
init(from decoder: Decoder) throws {
...
let personsDictionary = try container.decode([String: Person].self, forKey: .persons)
and then try to do:
persons = personsDictionary
of course it doesn't work at all. I tried to do all kinds of magic already with no luck. Does anyone have any solution to parsing dictionaries into ordered sequences or even Arrays? Thanks for helping!
There is NO WAY the JSON response changes into being an array and YES it always is the same order.
Both Swift, JSON Dictionaries are unordered by there nature. The JSON format does notmaintain key ordering, and as such, does not required parser to preserve the order.
If you need an ordered collection, you its better to returning an array of key-value pairs in the JSON
{
"persons": [
{ "John": {
"name": "John",
"age": 24
}
},
{"Michael": {
"name": "Michael",
"age": 44
}
},
{ "Jack": {
"name": "Jack",
"age": 25
}
}
]
}

swift parse json as per maintaining order

Suppose i have json string in which there is a json array called data.
The array holds json object of user profile data for example name,age,gender etc.
Now want to parse that json object as per order, for example if the object is
{
"name": "sample name",
"age": "30",
"gender": "male"
}
i want to parse the list as ordered like name,age,gender but with ios,when i convert the json object as dictionary , the order is changed,i know dictionary is not ordered so what is the the alternative to achieve this?
its a third party api so i dont have any hand on it,we have done it in android with linked hash map,but really stuck in swift , the last thing i would want to do is parse with regular expression.
im parsing the json in following way :
var rootData = try JSONSerialization.jsonObject(with: data!) as! [String:Any]
if let val = fromList["data"] {
let dataNode = val as! [[String:Any]]
for row in dataNode {
for (key,keyVal) in row {
//here the key is not in order.because when we cast it as dictionary the order gets changed.
}
}
For android we have achieved to do this with following function :
public ArrayList<LinkedHashMap<String, Object>> parseJsonArrayList(String odata, String arrayName) {
ArrayList<LinkedHashMap<String, Object>> mylist = new ArrayList<>();
try {
JSONObject e = new JSONObject(odata);
JSONArray data = e.getJSONArray(arrayName);
for(int i = 0; i < data.length(); ++i) {
JSONObject v = data.getJSONObject(i);
LinkedHashMap<String, Object> map = new LinkedHashMap<>(100, 0.75f, false);
Iterator keys = v.keys();
while(keys.hasNext()) {
String key = String.valueOf(keys.next());
//gph.log("debug4", key);
map.put(key, v.getString(key));
//gph.log("debug4", v.getString(key));
}
mylist.add(map);
}
} catch (JSONException var10) {
var10.printStackTrace();
}
return mylist;
}
Don’t try to order the dictionary. Instead create an array of the keys in the order you desire:
let keys = [“name”, “age”, “gender”]
Then access the dictionary with them:
for key in keys {
let value = dict[key]
// Present the value.
}
That will ensure the order you expect.
As you mentioned you cannot get the ordered data in Dictionary. If possible you can add the "order" key in your JSON like
[
{
"name": "sample name",
"order": 1
},
{
"age": "30",
"order": 1
},
{
"gender": "",
"male": "",
"order": 1
}
]
so that based on the order key you can do the sorting.

Pointer to inner nodes of JSON (NSDictionary)

{
"outterList": {
"section1": {
"entry1": {
"value": ""
},
"entry2": {
"value": ""
},
"entry3": {
"value": ""
},
"innerSection": {
"entry1": {
"value": ""
},
"entry2": {
"value": ""
}
}
},
"section2": {
"entry1": {
"value": ""
}
}
}
}
Problem statement is to read the above json and store it back in the same format with the "value" fields updated as per the local logic.
I initially go and parse the above NSDictionary and convert it to an NSArray (Mutable), which holds all the "entry" nodes in a custom holder class.
Is it possible that my NSArray's holder object can store a direct pointer to "outterList" -> "section1" -> "innerSection" -> "entry2", so that whenever I get a new value from my logic and I have to update it, I can do that immediately on the fly and not parsing it again to reach to that node.
Value in a dictionary will be changed if you modify the object itself:
myObj.value = newValue;
but it won't change if you simply assign pointer to another object:
myObj = [MyObj new];
so it won't work with JSON strings or numbers.
Also you can access dictionary values faster using valueForKeyPath like so:
[dict setValue:newValue forKeyPath:#"outterList.section1.entry1.value"]

SwiftyJSON how to append data

I try to create JSON with this structure:
var json: JSON = [
"params": [
"token": Utilities.token,
"language": "RU",
"billerId": biller.id,
],
"data": [
"serviceData": [
//I want put here additional data
]
]
]
in "serviceData" I want to add fields and values, but I don't know how much them and what is his name before compiling.
I try add this fields by this way:
for item in templateItems{
let key:String = item.name
let value: String = item.value
json["data"]["serviceData"][key] = value
}
according to https://github.com/SwiftyJSON/SwiftyJSON/tree/a1356035d2de68c155d05521292f0609ef7e69bb#literal-convertibles
but it doesn't work
It shouldn't be array, it is key-value dictionary.
Replace
"seviceData": []
With
"serviceData": [:]
The former defines an empty array. The latter defines an empty dictionary.

Resources