parsing JSON with Swift - ios

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 []")
}
}

Related

How can I parse an array into the json on Swift?

I need to take the value "maxtemp_c" from the json request, but it didn't work.
This is what I've do, It will block when I try to parse the json and the value is nil
//url of the json
let url = URL(string: "http://api.apixu.com/v1/forecast.json?key=6cffef39633d4489a0e101339171811&q=Loria&days=3")!
let taskfor = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print("some error occured")
} else {
if error == nil {
do{
let jsonResult = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String : AnyObject]
let forecast = jsonResult["forecast"] as? [String : AnyObject]
// I would not recommend to use NSDictionary, try using Swift types instead
guard let forecastday = forecast!["forecastday"] as? [[String:Any]] else { return }
// Check for the weather parameter as an array of dictionaries and than excess the first array's description
var finalArray:[Any] = []
//now I try to parse the json but the result is nil
for result in forecastday {
if let dict = result as? [String: Any], let forecastday = dict["day"] as? [String] {
finalArray.append(forecastday)
}
}
print(finalArray)
}catch {
print("JSON Preocessing failed")
}
}
}
}
taskfor.resume()
and this is the json that I have to parse
"forecast": {
"forecastday": [ //this is the problem that the value is nil
{
"date": "2017-11-26",
"date_epoch": 1511654400,
"day": {
"maxtemp_c": 7.3, //this is the value that I need
Looks like "day" key contains Dictionary not Array, just change it to [String: Any] from [String]
for result in forecastday {
if let dict = result as? [String: Any], let forecastday = dict["day"] as? [String: Any] {
finalArray.append(forecastday)
}
}
If you want just "maxtemp_c" array then declare final array as [Double] and add a check for "maxtemp_c" in the end
if let forecastday = forecast["forecastday"] as? [[String: Any]] {
var finalArray: [Double] = []
for result in forecastday {
if let dict = result as? [String: Any], let forecastday = dict["day"] as? [String: Any], let temp = forecastday["maxtemp_c"] as? Double {
finalArray.append(temp)
}
}
print(finalArray)
}
If you want "maxtemp_c" in [String] format then do
finalArray.append(String(format: "%.1f", temp))

Swift JSON extraction

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)")
}
}

How can I parse this JSON object using Swift 3.0

I'm trying to parse a JSON string returned from a new API. The returned JSON string looks like this.
QuerySearchResult":{
"StartAt":"1",
"Count":"40",
"TotalAvailable":"500",
"Items":[
{"TITLE":"OST420 Generation",
"PATH":"http:\\Test.pdf",
"WRITE":"2016-12-12T15:47:42",
"RANK":"32286574",
"SIZE":"145091",
"ISDOCUMENT":"true",
"ID":"18548",
"WPTASK":"Onsite Generation",
"WPDOCTYPE":"Local Operating Procedure",
"WPDOCREFID":"304580",
"WPCONTENTTYPE":"Document"},
{"TITLE":"OST420 Measurement",
"PATH":"http:\Test33.pdf",
.
.
I'm using the code below which accepts the JSON variable but fails when I try to load item. I've tried using Array around Dictionary but it still fails. What declaration do I need to read in Items?
if let json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as? Dictionary<String, AnyObject> {
for item in json {
if let dict = item as? Dictionary<String, AnyObject> {
if let items = json["Items"] as? Array<Dictionary<String, AnyObject>> {
for rec in items {
if let title = rec["TITLE"] as? String {
let xx = title
}
}
}
}
}
First of all you are not correctly iterating through Dictionary also instead of looping through Dictionary for accessing single value, try by directly accessing it through subscripting and the proper JSON notation of Dictionary in Swift 3 is [String : Any].
if let json = try? JSONSerialization.jsonObject(with: data!, options: []) as? [String : Any],
let queryDic = json["QuerySearchResult"] as? [String : Any],
let items = queryDic["Items"] as? [[String : Any]] {
for item in items {
if let title = item["TITLE"] as? String {
print(title)
}
}
}
In Swift 3.1 :-
func parseJson(anyObj:AnyObject) {
if let anyObj = anyObj as? Array<Dictionary<String,AnyObject>> {
self.yourArrayName = anyObj.flatMap({yourModelName(json:$0) })
}
}
The Json returns the data into the dictionary and array format, so treat the json data like it, it makes you easier to understand.
Data in braces '{' and '}' is dictionary.
and Data in braces '[' or ']' is array.
Now start parsing the json data by the dictionary and array properties it exactly works. Or for confirmation print your json data.
Use SwiftyJSON : which can simply and easily parse the JSON more than your code.
So, how do we parse using that?
First get your response as Data()
let jsonData = JSON(data: results!)
Then here how we parse that JSON.
import Foundation
import SwiftyJSON
enum JSONParseError : ErrorType {
case UnknownField
case EmptyJSON
}
extension JSONParseError : CustomStringConvertible {
var description: String {
switch self {
case .UnknownField:
return "Error when parsing json because there is no field"
case .EmptyJSON:
return "Error when parsing empty json"
}
}
}
guard let querySearchResult : [String : JSON] = jsonData["QuerySearchResult"].dictionary else{
throw JSONParseError.UnknownField
}
guard let startAt : String = querySearchResult["StartAt"].string else{
throw JSONParseError.UnknownField
}
guard let count : String = querySearchResult["Count"].string else{
throw JSONParseError.UnknownField
}
guard let totalAvailable : String = querySearchResult["TotalAvailable"].string else{
throw JSONParseError.UnknownField
}
guard let items : [JSON] = querySearchResult["Items"].array else{
throw JSONParseError.UnknownField
}
if items.count > 0 {
for i in 0 ..< items.count{
guard let title = items[i]["TITLE"].string else{
throw JSONParseError.UnknownField
}.... //So On
}
}else{
throw JSONParseError.EmptyJSON
}

What is the different between these two rows in the JSON array which means one isn't being recognised?

I have an API call that retrieves an array from my database featuring countries, divisions, teams.
This output shows the format of the JSON when received in Swift (teams not shown in example:
Optional(["countries": <__NSArrayI 0x6180001f6500>(
{
id = 1;
name = Denmark;
},
{
id = 2;
name = Belgium;
}
)
, "divisions": <__NSArrayI 0x7fc8a34455a0>(
{
Name = "ALKA SUPERLIGA";
"country_id" = 1;
id = 1;
},
{
Name = "PRO LEAGUE";
"country_id" = 2;
id = 2;
}
I am using the following function in swift to sort the countries and divisions into different string arrays to then use in an UITableView.
override func viewDidAppear(_ animated: Bool) {
let myUrl = URL(string: "http://www.quasisquest.uk/KeepScore/getTeams.php?");
var request = URLRequest(url:myUrl!);
request.httpMethod = "POST";
let postString = "";
request.httpBody = postString.data(using: String.Encoding.utf8);
let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
DispatchQueue.main.async
{
if error != nil {
print("error=\(error)")
return
}
do{
let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:AnyObject]
print (json)
if let arr = json?["countries"] as? [[String:String]] {
self.countryId = arr.flatMap { $0["id"]!}
self.countries = arr.flatMap { $0["name"]!}
self.teamsTableView.reloadData()
print ("Countries: ",self.countries)
}
if let arr = json?["divisions"] as? [[String:String]] {
self.divisions = arr.flatMap { $0["Name"]!}
self.divisionId = arr.flatMap { $0["id"]!}
self.teamsTableView.reloadData()
print ("Divisions: ",self.divisions)
}
} catch{
print(error)
}
}
}
task.resume()
//membersTableView.reloadData()
}
The print ("Countries: ",self.countries) outputs as expected, below:
Countries: [Optional("Denmark"), Optional("Belgium")
But the print ("Divisions: ",self.divisions) doesn't even run. So there must be something wrong with that IF command, yet I am using the same code as what I used from the 'countries' section.
Any ideas?
I have tried replacing [[String : String]] with [[String : String?]] but this did nothing. I have also tried [[String : Any]] but this brought the following error on the arr.flapMap lines:
'(_) -> Any' to expected argument type '(Dictionary) -> SegmentOfResult'
First of all in Swift 3 the common unspecified type is Any rather than AnyObject
In the given JSON
The root object is [String:Any]
The value for divisions is [[String:Any]] because it contains String and <null> types.
The value <null> will be replaced with n/a
if let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:Any] {
print (json)
if let arr = json["countries"] as? [[String:String]] {
self.countryId = arr.flatMap { $0["id"]!}
self.countries = arr.flatMap { $0["name"]!}
self.teamsTableView.reloadData()
print ("Countries: ",self.countries)
}
if let arr = json["divisions"] as? [[String:Any]] {
self.divisions = arr.flatMap { $0["Name"] as? String ?? "n/a" }
self.divisionId = arr.flatMap { $0["id"] as? String }
self.teamsTableView.reloadData()
print ("Divisions: ",self.divisions)
}
}
Notes:
Do not use multiple arrays as data source in conjunction with flatMap, this is pretty error-prone, use a custom struct instead.
A POST request is not needed, GET (a data task passing the url) is sufficient.
Probably "country_id" key has integer value and because of that "if let arr = json?["divisions"] as? [[String:String]]" statement is not working.
Always try to set [[String:Any]] to any array of dictionary if you retrieving it from server.
Your dictionary is of type [String:Any], thus the cast fails. Use Any:
if let arr = json?["divisions"] as! [[String:Any]] { ...
It happens because in case of divisions some elements contain empty (null) names. Which means that real type is not [[String:String]], but [[String:String?]]

swift: cannot subscript a value of type [Dictionary<String, AnyObject>] with an index of type string

I am trying to json parsing in swift 3. I am getting the above mentioned error. My parsing technique is as follows:
if let responseData = data {
do {
let json = try JSONSerialization.jsonObject(with: responseData, options: JSONSerialization.ReadingOptions.allowFragments)
if let dict = json as? [Dictionary<String, AnyObject>] {
if let localityName = dict["name"] as? String ,let localityId = dict["_id"] as? String {
}
}
} catch {
print("could not serialize")
}
}
I am getting the error in the line:
if let localityName = dict["name"] as? String ,let localityId = dict["_id"] as? String
please let me know how can I fix this issue
The dict property is an array of dictionaries, not a dictionary.
You could access the first elements name the following:
dict.first?["name"]
dict is actually arr. Create a loop to iterate thru it
if let arr = json as? [Dictionary<String, AnyObject>] {
for item in arr {
if let localityName = item["name"] as? String,
let localityId = item["_id"] as? String {
print(localityName, localityId)
}
}
}

Resources