Swift JSON extraction - ios

I am developing a swift iOS app and getting the following JSON response from web service. I am trying to parse and get nextResponse from it. I am unable to extract it. Could someone guide me to solve this?
listofstudents:
({
studentsList = (
{
data = (
"32872.23",
"38814.87",
"38915.85"
);
label = “name, parents and guardians”;
}
);
dateList = (
"Apr 26, 2017",
"Jun 10, 2017",
"Jul 26, 2017"
);
firstResponse = “This school has 1432 students and 387 teachers.”;
nextResponse = “This school has around 1400 students.”;
})
Swift code:
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
print("json: \(json)")
if let parseJSON = json {
let finalResponse = parseJSON["listofstudents"] as? AnyObject
print("listofstudents:: \(finalResponse)")
let nextResponse = parseJSON["nextResponse"] as? AnyObject
print("nextResponse:: \(nextResponse)")
}
} catch {
print(error)
}

Don't use NSDictionary in Swift, but use its native Swift counterpart, Dictionary. This is how you access dictionaries embedded inside other dictionaries:
do {
guard let json = try JSONSerialization.jsonObject(with: data!) as? [String:Any] else {return}
print("json: \(json)")
guard let finalResponse = parseJSON["listofstudents"] as? [String:Any] else {return}
print("listofstudents:: \(finalResponse)")
guard let nextResponse = finalResponse["nextResponse"] as? [String:Any] else {return}
print("nextResponse:: \(nextResponse)")
} catch {
print(error)
}

nextResponse is part of the JSON structure (it's a nested node). So you should access it using:
typealias JSON = [String: Any]
if let finalResponse = parseJSON["listofstudents"] as? JSON {
let nextResponse = finalResponse ["nextResponse"] as? JSON
print("nextResponse:: \(nextResponse)")
}

Looks like your listofstudents is an array of dictionary so try to iterate it and extract it:-
if let finalResponse = parseJSON["listofstudents"] as? [String: Any] {
//If your finalResponse has list then you can print all the data
for response in finalResponse {
let nextResponse = finalResponse ["nextResponse"] as? AnyObject
print("nextResponse::\(nextResponse)")
}
}

Related

Working with JSON data retrieving into Swift data types

I'm trying to get data from a URL. It was successful. I can download and convert to a dictionary[String : Any] but response is in nested loops. I don't to how to retrieve. Can someone suggest how to get text and value in the response?
func getDataFromUrl() {
let url = URL(string: "https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&departure_time=1408046331&origins=37.407585,-122.145287&destinations=37.482890,-122.150235")
let request = NSMutableURLRequest(url: url!)
let session = URLSession.shared
request.httpMethod = "GET"
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: {(data, response, error) in
do {
let jsonData = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String: Any]
let destinationAddress = jsonData!["destination_addresses"]
print("Destination address \(String(describing: destinationAddress!))")
let origin_addresses = jsonData!["origin_addresses"]
print("Origin_addresses \(String(describing: origin_addresses!))")
let rows = jsonData!["rows"]
print("Rows \(String(describing: rows!))")
// Here I want to print text and value.
} catch {
// handle error
}
})
dataTask.resume()
}
The above answers work, but in my opinion the more swiftier approach is to use Codable.
class MyResponseType:Codable {
let destination_addresses:String
let rows:[MyCustomRowData]
}
class MyCustomRowData:Codable {
let elements:[MyCustomElementsData]
}
class MyCustomElementsData:Codable {
// properties here
}
Doing this, parsing the json is done like this:
let response = try? JSONDecoder().decode(MyResponseType.self, from: data)
Where the data variable is just the retrieved Data object from the request.
Initially you have to set up some boilerplate code to replicate your expected data format, but working with it is really worth it (and it makes it highly testable).
When the decode succeeds you have a perfectly typed object, it can also have optionals. It just wont decode if fields are missing or of the wrong type (which is a good thing).
Here is the way you can parse text and Value from response:
do{
if let jsonData = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String: Any] {
if let destinationAddress = jsonData["destination_addresses"] as? [String] {
print(destinationAddress) //["1 Hacker Way, Menlo Park, CA 94025, USA"]
}
if let origin_addresses = jsonData["origin_addresses"] as? [String] {
print(origin_addresses) //["3251 Hillview Ave, Palo Alto, CA 94304, USA"]
}
if let rows = jsonData["rows"] as? [[String: AnyObject]] {
if rows.indices.contains(0) {
if let elements = rows[0]["elements"] as? [[String: AnyObject]] {
for element in elements {
if let duration = element["duration"] as? [String: AnyObject] {
let text = duration["text"] as? String ?? ""
print(text) //17 mins
let value = duration["value"] as? Int ?? 0
print(value) //1010
}
if let distance = element["distance"] as? [String: AnyObject] {
let text = distance["text"] as? String ?? ""
print(text) //7.2 mi
let value = distance["value"] as? Int ?? 0
print(value) //11555
}
}
}
}
}
}
}catch{ //error handle
}
Use this code:
let rows = jsonData["rows"] as! Array
let element = rows[0] as! Dictionary
let elementArray = element.value(forKey: "elements")
let distance = elementArray[0].value(forKey: "distance")
let text = distance.value(forKey: "text")
print(text)
let value = distance.value(forKey: "value")
print(value)

Convert Json string to Json object in Swift 4

I try to convert JSON string to a JSON object but after JSONSerialization the output is nil in JSON.
Response String:
[{\"form_id\":3465,\"canonical_name\":\"df_SAWERQ\",\"form_name\":\"Activity 4 with Images\",\"form_desc\":null}]
I try to convert this string with my code below:
let jsonString = response.result.value
let data: Data? = jsonString?.data(using: .utf8)
let json = (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String:AnyObject]
print(json ?? "Empty Data")
The problem is that you thought your jsonString is a dictionary. It's not.
It's an array of dictionaries.
In raw json strings, arrays begin with [ and dictionaries begin with {.
I used your json string with below code :
let string = "[{\"form_id\":3465,\"canonical_name\":\"df_SAWERQ\",\"form_name\":\"Activity 4 with Images\",\"form_desc\":null}]"
let data = string.data(using: .utf8)!
do {
if let jsonArray = try JSONSerialization.jsonObject(with: data, options : .allowFragments) as? [Dictionary<String,Any>]
{
print(jsonArray) // use the json here
} else {
print("bad json")
}
} catch let error as NSError {
print(error)
}
and I am getting the output :
[["form_desc": <null>, "form_name": Activity 4 with Images, "canonical_name": df_SAWERQ, "form_id": 3465]]
Using JSONSerialization always felt unSwifty and unwieldy, but it is even more so with the arrival of Codable in Swift 4. If you wield a [String:Any] in front of a simple struct it will ... hurt. Check out this in a Playground:
import Cocoa
let data = "[{\"form_id\":3465,\"canonical_name\":\"df_SAWERQ\",\"form_name\":\"Activity 4 with Images\",\"form_desc\":null}]".data(using: .utf8)!
struct Form: Codable {
let id: Int
let name: String
let description: String?
private enum CodingKeys: String, CodingKey {
case id = "form_id"
case name = "form_name"
case description = "form_desc"
}
}
do {
let f = try JSONDecoder().decode([Form].self, from: data)
print(f)
print(f[0])
} catch {
print(error)
}
With minimal effort handling this will feel a whole lot more comfortable. And you are given a lot more information if your JSON does not parse properly.
I tried the solutions here, and as? [String:AnyObject] worked for me:
do{
if let json = stringToParse.data(using: String.Encoding.utf8){
if let jsonData = try JSONSerialization.jsonObject(with: json, options: .allowFragments) as? [String:AnyObject]{
let id = jsonData["id"] as! String
...
}
}
}catch {
print(error.localizedDescription)
}
I used below code and it's working fine for me. :
let jsonText = "{\"userName\":\"Bhavsang\"}"
var dictonary:NSDictionary?
if let data = jsonText.dataUsingEncoding(NSUTF8StringEncoding) {
do {
dictonary = try NSJSONSerialization.JSONObjectWithData(data, options: [.allowFragments]) as? [String:AnyObject]
if let myDictionary = dictonary
{
print(" User name is: \(myDictionary["userName"]!)")
}
} catch let error as NSError {
print(error)
}
}
static func getJSONStringFromObject(object: Any?) -> String? {
do {
let jsonData = try JSONSerialization.data(withJSONObject: object ?? DUMMY_STRING, options: [])
return String(data: jsonData, encoding: .utf8) ?? DUMMY_STRING
} catch {
print(error.localizedDescription)
}
return DUMMY_STRING
}

how to get the JSONArray from jsonObject in Swift 3.1

{
"status": true,
"status_code": 1,
"content": [
{
"cat_id": "3",
"cat_name": "Food",
"cat_parentid": "2"
},
{
"cat_id": "4",
"cat_name": "Entertainment",
"cat_parentid": "2"
},
{
"cat_id": "5",
"cat_name": "Cars",
"cat_parentid": "2"
},
{
"cat_id": "12",
"cat_name": "Personal Care",
"cat_parentid": "2"
}
],
"message": "Success"
}
UPDATE
do {
//create json object from data
if let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
completion((json as? AnyObject)!) //here completion callback will return the jsonObject to my UIViewController.
}
} catch let error {
print(error.localizedDescription)
}
this is my JSONObject. I am very new to the swift. how to get the content JSONArray and further process in swift.? Anybody can help me? Help will be appreciated.
This code checks if the status is true, gets the array for key content and prints all values in the array.
The array is clearly [[String:String]] so cast the object to this specific type.
do {
//create json object from data
if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] {
if let status = json["status"] as? Bool, status == true {
if let content = json["content"] as? [[String:String]] {
for category in content {
let id = category["cat_id"]
let name = category["cat_name"]
let parentId = category["cat_parentid"]
print(id , name, parentId)
}
}
}
}
} catch let error {
print(error.localizedDescription)
}
PS: As always, never use .mutableContainers in Swift. It's meaningless
Check whether your json has content array
if let content = json["content"] as? [Dictionary<String, AnyObject>] {
print(content) // it will give you content array
}
Get content array like this:
let allContent = json["content"] as? [[String: Any]]
Full sample:
do {
//create json object from data
if let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
if let allContent = json["content"] as? [[String: Any]] {
for content in allContent {
let catId = content["cat_id"] as? String
let catName = content["cat_name"] as? String
let catParentId = content["cat_parentid"] as? String
print(">> catid=" + catId!)
print(">> catName=" + catName!)
print(">> catparentID=" + catParentId!)
}
}
}
} catch let error {
print(error.localizedDescription)
}
let content = dict.objectForKey("content")! as NSArray
Then you can get json of single object for parsing by
for var cat in content
{
print(cat)
}
Another alternative way, by using the library.
First, import JSON library for Swift - SwiftyJSON and use the code:
import SwiftyJSON
let json = JSON(<jsonObject data>)
let contentArray: Array<JSON> = json["content"].arrayValue
Library Integration
If you're using cocoapods then use this pod:
pod 'SwiftyJSON'
OR else just drag SwiftyJSON.swift to the project tree.
you can extract you data by providing key
if let array = result["content"] as? Array<AnyObject> {
print(arry)
}
You can access like below
if let filePath = Bundle.main.path(forResource: "sample", ofType: "json"), let data = FileManager().contents(atPath: filePath) {
do {
let dicRes = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any]
let contentArray = dicRes?["content"]
print("contentArray == \(contentArray)")
} catch {
}
}

Value of optional type 'NSDictionary??' not unwrapped

I've been following a tutorial that was playing around with API, specifically the openweathermap api, and I ran into a problem and xCode gives me options to "Fix it with ! and ??", which unfortunately does not fix the issue either.
if let urlContent = data {
do {
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String: Any]
print(jsonResult)
print(jsonResult?["name"])
if let description = ((jsonResult?["weather"] as? NSArray)?[0] as? NSDictionary)?["description"] as? String {
print(description)
}
} catch {
print("JSON Processing Fail")
}
Im getting an error on if let description = ((jsonResult?["weather"] as? NSArray)?[0] as? NSDictionary)?["description"] as? Stringas a Value of optional type 'NSDictionary??' not unwrapped Error.
Simply use Swift's native type Array instead of NSArray.
do {
if let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: []) as? [String: Any] {
if let weatherArray = jsonResult["weather"] as? [[String:Any]],
let dic = weatherArray.first, let description = dic["description"] as? String {
print(description)
}
}
} catch {
print("JSON Processing Fail")
}

parsing JSON with Swift

I'm coming from android programming to Swift iOS programming and have a hard time parsing a json
here's String I try to parse :
{"response":[{"uid":111,"first_name":"someName","last_name":"someLastName","photo_100":"http:someUrl/face.jpg"}]}
here how I try to parse this :
if let dict = Utils.convertStringToDictionary(response)! as? [String: AnyObject]{
// this part is yet doing ok
if let response = dict["response"] as? [String: AnyObject]{
NSLog("let response \(response)")
if let first_name = response["first_name"] as? String {
NSLog("first_name = \(first_name)")
}
}
else {
NSLog("not an []")
}
the Log message gives me "not an []" as it can't make a response object. As far as I understand, I'm doing right as [String: AnyObject] is what is in "response" body of my json
Just in case, here's my Utils.convertStringToDictionary method:
public static func convertStringToDictionary(text: String) -> [String:AnyObject]? {
if let data = text.dataUsingEncoding(NSUTF8StringEncoding) {
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers) as? [String:AnyObject]
return json
} catch {
NSLog("Something went wrong")
}
}
return nil
}
Array in swift denotes with []
Dictionary in swift denotes with [:]
your response parameter is array of dictionary ... so it denotes with [[:]]
so just parse it with [[String: AnyObject]]
if let response = dict["response"] as? [[String: AnyObject]]{
for user in response{
NSLog("let response \(user)")
if let first_name = user["first_name"] as? String {
NSLog("first_name = \(first_name)")
}
}
}
Problem here is response is an array
if let response = dict["response"] as? NSArray{
for value in response as? NSDictionary{
print(value["uid"]) /// prints 111
print(value["first_name"]) /// prints someName
}
}
Try this code
if let dict = Utils.convertStringToDictionary(response)! as? [String: AnyObject]{
// this part is yet doing ok
if let response = dict["response"] as? NSArray{
NSLog("let response \(response)")
for dict in response{
if let first_name = dict["first_name"] as? String {
NSLog("first_name = \(first_name)")
}
}
}
else{
NSLog("not an []")
}
}

Resources