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)
Have been researching on the parsing for quite a bit. With plethora of information avilable for JSON nothing seems to explain how to do in a sensible way to extract information with swift 3.
This is what got so far
func getBookDetails() {
let scriptUrl = "https://www.googleapis.com/books/v1/volumes?q=isbn:9781451648546" .
let myurl = URL(string:scriptUrl)
let request = NSMutableURLRequest(url: myurl!)
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: myurl! ) { (data, response, error) in
if error != nil{
print("THIS ERROR",error!)
return
} else{
if let mydata = data{
do{
let myJson = try (JSONSerialization.jsonObject(with: mydata, options: JSONSerialization.ReadingOptions.mutableContainers)) as AnyObject
// print("this is the MY JSON",myJson) ---> prints out the json
if let dictonary = myJson["items"] as AnyObject? {
print("the DICTONARY",dictonary) // ----> OUTPUT
if let dictonaryAA = dictonary["accessInfo"] as AnyObject? {
print("the accessInfo",dictonaryAA)
}
}
} catch{
print("this is the in CATCH")
}
} //data
}
}
task.resume()
}
}
OUTPUT :
the DICTONARY (
{
accessInfo = {
accessViewStatus = SAMPLE;
country = US;
=============
RELEVANT DATA as in https://www.googleapis.com/books/v1/volumes?
q=isbn:9781451648546"
==========================
title = "Steve Jobs";
};
}
)
Just need to parse through the json data to get the name, author and title of the book with reference to isbn.
Know there should be a better way to do things that is easily understandable to someone new into the language
You can parse the api in two ways
Using URLSession:
let rawDataStr: NSString = "data={\"mobile\":\"9420....6\",\"password\":\"56147180..1\",\"page_no\":\"1\"}"
self.parsePostAPIWithParam(apiName: "get_posts", paramStr: rawDataStr){ ResDictionary in
// let statusVal = ResDictionary["status"] as? String
self.postsDict = (ResDictionary["posts"] as! NSArray!) as! [Any]
print("\n posts count:",self.postsDict.count)
}
func parsePostAPIWithParam(apiName:NSString, paramStr:NSString,callback: #escaping ((NSDictionary) -> ())) {
var convertedJsonDictResponse:NSDictionary!
let dataStr: NSString = paramStr
let postData = NSMutableData(data: dataStr.data(using: String.Encoding.utf8.rawValue)!)
let request = NSMutableURLRequest(url: NSURL(string: "http://13.12..205.248/get_posts/")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = nil
request.httpBody = postData as Data
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error as Any)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse as Any)
do{
if let convertedJsonIntoDict = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary {
convertedJsonDictResponse = convertedJsonIntoDict.object(forKey: apiName) as? NSDictionary
// callback for response
callback(convertedJsonDictResponse)
}
} catch let error as NSError {
print(error)
}
}
Using Alamofire
func AlamofirePOSTRequest() {
let urlString = "http://13.12..205.../get_posts/"
let para = ["data": "{\"mobile\":\"9420....6\",\"password\":\"56147180..1\",\"page_no\":\"1\"}"]
Alamofire.request(urlString, method: .post, parameters: para , headers: nil).responseJSON {
response in
switch response.result {
case .success:
print("response: ",response)
let swiftyJsonVar = JSON(response.result.value!)
if let resData = swiftyJsonVar["posts"].arrayObject {
self.postsDict = resData as! [[String:AnyObject]]
}
print("\n \n alomafire swiftyJsonVar: ",swiftyJsonVar)
break
case .failure(let error):
print(error)
}
}
}
})
dataTask.resume()
}
First of all, all JSON types are value types in Swift 3 so the most unspecified type is Any, not AnyObject.
Second of all, there are only two collection types in the JSON type set, dictionary ([String:Any]) and array ([Any], but in most cases [[String:Any]]). It's never just Any nor AnyObject.
Third of all, the given JSON does not contain a key name.
For convenience let's use a type alias for a JSON dictionary:
typealias JSONDictionary = [String:Any]
The root object is a dictionary, in the dictionary there is an array of dictionaries for key items. And pass no options, .mutableContainers is nonsense in Swift.
guard let myJson = try JSONSerialization.jsonObject(with: mydata) as? JSONDictionary,
let items = myJson["items"] as? [JSONDictionary] else { return }
Iterate through the array and extract the values for title and authors which is an array by the way. Both values are in another dictionary for key volumeInfo.
for item in items {
if let volumeInfo = item["volumeInfo"] as? JSONDictionary {
let title = volumeInfo["title"] as? String
let authors = volumeInfo["authors"] as? [String]
print(title ?? "no title", authors ?? "no authors")
The ISBN information is in an array for key industryIdentifiers
if let industryIdentifiers = volumeInfo["industryIdentifiers"] as? [JSONDictionary] {
for identifier in industryIdentifiers {
let type = identifier["type"] as! String
let isbn = identifier["identifier"] as! String
print(type, isbn)
}
}
}
}
You are doing wrong in this line
if let dictonaryAA = dictonary["accessInfo"] as AnyObject?
because dictonary here is an array not dictionary. It is array of dictionaries. So as to get first object from that array first use dictonary[0], then use accessInfo key from this.
I am attaching the code for your do block
do{
let myJson = try (JSONSerialization.jsonObject(with: mydata, options: JSONSerialization.ReadingOptions.mutableContainers)) as AnyObject
// print("this is the MY JSON",myJson) ---> prints out the json
if let array = myJson["items"] as AnyObject? {
print("the array",array) // ----> OUTPUT
let dict = array.object(at: 0) as AnyObject//Master Json
let accessInf = dict.object(forKey: "accessInfo") //Your access info json
print("the accessInfo",accessInf)
}
}
Hope this helps you.
Code
func callAddWithPOST(Name mname:String, PhoneNo mphone:String, Email memail:String, Comment mcomments:String){
var names = [String]()
let login = ["countryId":"1"]
print("Your Result is : = \(login)")
let url = NSURL(string: "http://photokeeper.mgtcloud.co.uk/commonwebservice.asmx/getStateList")!
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: url)
do {
let auth = try NSJSONSerialization.dataWithJSONObject(login, options: .PrettyPrinted)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.HTTPMethod = "POST"
request.HTTPBody = auth
let task = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
let badJsonString = "This really isn't valid JSON at all"
let badJsonData = badJsonString.dataUsingEncoding(NSUTF8StringEncoding)!
do {
let parsed = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments)
print(parsed)
let otherParsed = try NSJSONSerialization.JSONObjectWithData(badJsonData, options: NSJSONReadingOptions.AllowFragments)
}
catch let error as NSError {
print("A JSON parsing error occurred, here are the details:\n \(error)")
}
print("Done.")
})
task.resume()
} catch {
print("Error")
}}
OUTPUT
{
d = "{\"result\":[{\"stateId\":3871,\"stateName\":\"Aberdeenshire\"},{\"stateId\":3872,\"stateName\":\"Anglesey/Sir Fon\"},{\"stateId\":3873,\"stateName\":\"Angus\"},{\"stateId\":3874,\"stateName\":\"Antrim\"},{\"stateId\":3875,\"stateName\":\"Argyll And Bute\"},{\"stateId\":3876,\"stateName\":\"Armagh\"},{\"stateId\":3877,\"stateName\":\"Ayrshire\"},{\"stateId\":3878,\"stateName\":\"Bedfordshire\"},{\"stateId\":3879,\"stateName\":\"Berkshire\"},{\"stateId\":3880,\"stateName\":\"Blaenau Gwent/Blaenau Gwent\"},{\"stateId\":3881,\"stateName\":\"Bristol\"},{\"stateId\":3882,\"stateName\":\"Buckinghamshire\"},{\"stateId\":3883,\"stateName\":\"Caerphilly/Caerffili\"},{\"stateId\":3884,\"stateName\":\"Cambridgeshire\"},{\"stateId\":3885,\"stateName\":\"Cardiff/Caerdydd\"},{\"stateId\":3886,\"stateName\":\"Cardiganshire/Ceredigion\"},{\"stateId\":3888,\"stateName\":\"Carmarthenshire/Sir Gaerfyrddin\"},{\"stateId\":3890,\"stateName\":\"Cheshire\"},{\"stateId\":3891,\"stateName\":\"Clackmannanshire\"},{\"stateId\":3893,\"stateName\":\"Conwy/Conwy\"},{\"stateId\":3895,\"stateName\":\"County Durham\"},{\"stateId\":3896,\"stateName\":\"Cumbria\"},{\"stateId\":3897,\"stateName\":\"Denbighshire/Sir Ddinbych\"},{\"stateId\":3898,\"stateName\":\"Derbyshire\"},{\"stateId\":3899,\"stateName\":\"Devon\"},{\"stateId\":3901,\"stateName\":\"Dorset\"},{\"stateId\":3902,\"stateName\":\"Down\"},{\"stateId\":3904,\"stateName\":\"Dumfries And Galloway\"},{\"stateId\":3905,\"stateName\":\"Dunbartonshire\"},{\"stateId\":3906,\"stateName\":\"Dundee\"},{\"stateId\":3907,\"stateName\":\"Durham/North Yorkshire\"},{\"stateId\":3908,\"stateName\":\"East Lothian\"},{\"stateId\":3909,\"stateName\":\"East Sussex\"},{\"stateId\":3910,\"stateName\":\"East Yorkshire\"},{\"stateId\":3911,\"stateName\":\"Edinburgh\"},{\"stateId\":3912,\"stateName\":\"Essex\"},{\"stateId\":3913,\"stateName\":\"Fermanagh\"},{\"stateId\":3914,\"stateName\":\"Fife\"},{\"stateId\":3915,\"stateName\":\"Flintshire/Sir Fflint\"},{\"stateId\":3917,\"stateName\":\"Glamorgan/Morgannwg\"},{\"stateId\":3918,\"stateName\":\"Glasgow\"},{\"stateId\":3919,\"stateName\":\"Gloucestershire\"},{\"stateId\":3920,\"stateName\":\"Gwynedd/Gwynedd\"},{\"stateId\":3921,\"stateName\":\"Hampshire\"},{\"stateId\":3922,\"stateName\":\"Herefordshire\"},{\"stateId\":3923,\"stateName\":\"Hertfordshire\"},{\"stateId\":3924,\"stateName\":\"Highland\"},{\"stateId\":3925,\"stateName\":\"Kent\"},{\"stateId\":3929,\"stateName\":\"Lanarkshire\"},{\"stateId\":3930,\"stateName\":\"Lancashire\"},{\"stateId\":3932,\"stateName\":\"Leicestershire\"},{\"stateId\":3935,\"stateName\":\"Lincolnshire\"},{\"stateId\":3936,\"stateName\":\"London\"},{\"stateId\":3937,\"stateName\":\"Londonderry\"},{\"stateId\":3940,\"stateName\":\"Manchester\"},{\"stateId\":3943,\"stateName\":\"Merthyr Tydfil/Merthyr Tydfil\"},{\"stateId\":3944,\"stateName\":\"Midlothian\"},{\"stateId\":3946,\"stateName\":\"Monmouthshire/Sir Fynwy\"},{\"stateId\":3947,\"stateName\":\"Moray\"},{\"stateId\":3948,\"stateName\":\"Neath Port Talbot\"},{\"stateId\":3949,\"stateName\":\"Newport\"},{\"stateId\":3950,\"stateName\":\"Norfolk\"},{\"stateId\":3951,\"stateName\":\"Northamptonshire\"},{\"stateId\":3952,\"stateName\":\"Northumberland\"},{\"stateId\":3953,\"stateName\":\"Nottinghamshire\"},{\"stateId\":3955,\"stateName\":\"Orkney\"},{\"stateId\":3956,\"stateName\":\"Oxfordshire\"},{\"stateId\":3957,\"stateName\":\"Pembrokeshire/Sir Benfro\"},{\"stateId\":3958,\"stateName\":\"Perth And Kinross\"},{\"stateId\":3959,\"stateName\":\"Powys/Powys\"},{\"stateId\":3960,\"stateName\":\"Renfrewshire\"},{\"stateId\":3962,\"stateName\":\"Rutland\"},{\"stateId\":3963,\"stateName\":\"Scottish Borders\"},{\"stateId\":3964,\"stateName\":\"Shetland Isles\"},{\"stateId\":3965,\"stateName\":\"Shropshire\"},{\"stateId\":3967,\"stateName\":\"Somerset\"},{\"stateId\":3968,\"stateName\":\"South Yorkshire\"},{\"stateId\":3969,\"stateName\":\"Staffordshire\"},{\"stateId\":3970,\"stateName\":\"Stirling\"},{\"stateId\":3971,\"stateName\":\"Suffolk\"},{\"stateId\":3972,\"stateName\":\"Surrey\"},{\"stateId\":3973,\"stateName\":\"Swansea\"},{\"stateId\":3975,\"stateName\":\"Torfaen\"},{\"stateId\":3976,\"stateName\":\"Tyrone\"},{\"stateId\":3977,\"stateName\":\"Warwickshire\"},{\"stateId\":3979,\"stateName\":\"West Lothian\"},{\"stateId\":3980,\"stateName\":\"West Midlands\"},{\"stateId\":3981,\"stateName\":\"West Sussex\"},{\"stateId\":3982,\"stateName\":\"West Yorkshire\"},{\"stateId\":3983,\"stateName\":\"Western Isles\"},{\"stateId\":3987,\"stateName\":\"Wiltshire\"},{\"stateId\":3988,\"stateName\":\"Worcestershire\"},{\"stateId\":3989,\"stateName\":\"Wrexham\"}],\"status\":\"success\"}";
}
A JSON parsing error occurred, here are the details:
Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.}
Done.
I AM GETTING ERROR - Invalid value around character 0. I want to get data in proper format with desired key and value, will anybody please help me to fix this issues.
Your JSON response is corrupted. Use JSONLint to verify it.
Convert it from
{\"result\":[{\"stateId\":3871,\"stateName\":\"Aberdeenshire\"}
to
{
"result": {
"stateId": 3871,
"stateName": "Aberdeenshire"
}
}
Notice the removal of the backslashes.
Looks like you are getting String in your response, so try something like this.
do {
let parsed = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments) as! [String: AnyObject]
let responseStr = parsed["d"] as! String
let correctData = responseStr.dataUsingEncoding(NSUTF8StringEncoding)
let responseDic = try NSJSONSerialization.JSONObjectWithData(correctData, options: NSJSONReadingOptions.AllowFragments) as! [String: AnyObject]
print(responseDic)
}
catch let error as NSError {
print("A JSON parsing error occurred, here are the details:\n \(error)")
}
Try this,
if let result:String = parsed["d"]! {
let result = convertStringToDictionary(text: result)
print("Converted result = \(result)")
}
//SWIFT 3
func convertStringToDictionary(text: String) -> [String:AnyObject]? {
if let data = text.data(using: String.Encoding.utf8) {
do {
return try JSONSerialization.jsonObject(with: data, options: []) as? [String:AnyObject]
} catch let error as NSError {
print(error)
}
}
return nil
}
//SWIFT 2
func convertStringToDictionary(text: String) -> [String:AnyObject]? {
if let data = text.dataUsingEncoding(NSUTF8StringEncoding) {
do {
return try NSJSONSerialization.JSONObjectWithData(data, options: []) as? [String:AnyObject]
} catch let error as NSError {
print(error)
}
}
return nil
}
I am safely unwrapping, but for some reason the app is still crashing when it cannot find the song equal to the given title. Why is this happening? How can I fix this?
let searchTerm: String = playertitle.text!
let itunesSearchTerm = searchTerm.stringByReplacingOccurrencesOfString(" ", withString: "+", options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil)
if let escapedSearchTerm = itunesSearchTerm.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) {
let urlPath = "https://itunes.apple.com/search?term=\(escapedSearchTerm)&media=music"
let url: NSURL = NSURL(string: urlPath)!
print("Search iTunes API at URL \(url)")
let task = NSURLSession.sharedSession().dataTaskWithURL(url) {(data, response, error) -> Void in
do {
if let dict: NSDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary
{
let previewUrl = NSURL(string: (dict["results"]![0]["previewUrl"] as? String)!)!
print(previewUrl)
player = AVPlayer(URL: previewUrl)
}
} catch let jsonError as NSError {
}
}
task.resume()
}
}
Guard the response data something like follows,
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
dispatch_async(dispatch_get_main_queue()) {
guard data != nil else {
print("response String is nil")
completionHandler(nil, error)
return
}
//completionHandler goes here
}
}
task.resume()
You are safe unwrapping a dictionary and not the results of it. If lets should go one for every possible value. Or take a look at SwiftyJSON framework it allows for lesser if lets.
Don't force unwrap (!) data! It might be nil. Use if let or guard.
if let data = data as? NSData,
let dict: NSDictionary = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary
While you're at it, check the error parameter too.
When parsing the data, nil might be returned everywhere. So be safe here too. Get rid of all force unwraps.
if let firstResult = dict["results"]?.first as? NSDictionary,
let preview = firstResult["previewUrl"] as? String,
let previewUrl = NSURL(string: preview) {
...
}