How to parse a api for swift 3? - ios

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.

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)

Passing data from JSON to table view cell in Swift 3

I'm trying to pass data from a JSON response to a table view cell. I'm having problems with capturing the response values that I'm extracting in URLSession.shared.dataTask.
func callYouTubeAPIToGetAllVideos() {
let url = URL(string: "https://www.googleapis.com/youtube/v3/search?part=snippet&channelId=XYZ&maxResults=50&order=date&key=ABC")
let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil {
print(error!)
} else {
if let usableData = data {
let json = try? JSONSerialization.jsonObject(with: usableData, options: [])
if let dictionary = json as? [String: Any?] {
if let array = dictionary["items"] as? [Any] {
for object in array {
if let objectAsDictionary = object as? [String: Any?] {
if let objectWithKindAndVideoId = objectAsDictionary["id"] as? [String: String] {
if let videoId = objectWithKindAndVideoId["videoId"] {
//pass data to table cell
}
}
if let snippet = objectAsDictionary["snippet"] as? [String: Any] {
if let description = snippet["description"] {
//pass data to table cell
}
}
}
}
}
}
}
}
}
task.resume()
}
I tried appending the values to an instance variable but it didn't work.
Sorry about the messy code, this is my 1st time working with JSON in Swift.
First of all never declare a received JSON dictionary as [String:Any?]. A received dictionary value can't be nil.
Declare a custom struct Video.
struct Video {
let videoId : String
let description : String
}
Declare a data source array.
var videos = [Video]()
Parse the JSON into the array and reload the table view on the main thread.
func callYouTubeAPIToGetAllVideos() {
let url = URL(string: "https://www.googleapis.com/youtube/v3/search?part=snippet&channelId=XYZ&maxResults=50&order=date&key=ABC")
let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil {
print(error!)
} else {
do {
if let dictionary = try JSONSerialization.jsonObject(with: data!) as? [String: Any],
let array = dictionary["items"] as? [[String: Any]] {
for object in array {
if let objectWithKindAndVideoId = object["id"] as? [String: String],
let snippet = object["snippet"] as? [String: Any] {
let videoId = objectWithKindAndVideoId["videoId"] ?? ""
let description = snippet["description"] as? String ?? ""
let video = Video(videoId: videoId, description: description)
self.videos.append(video)
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
} catch {
print(error)
}
}
}
task.resume()
}
In cellForRow assign the values to the text properties
let video = videos[indexPath.row]
cell.textLabel!.text = video.videoId
cell.detailTextLabel?.text = video.description

How to parse JSON using Alamofire in Swift 3.0 without any third-party library

Here I want to parse JSON via url. This is what actual JSON data available on url. So I need to parse it and read in my app using Alamofire. But I 'm unable to do it.
JSON Data in my url.
{
"main": [
{
"date": "2017-01-11",
"USDARS": "15.8302",
"USDCLP": "670.400024",
"USDSDG": "6.407695"
},
{
"date": "2017-01-12",
"USDARS": "15.804999",
"USDCLP": "661.599976",
"USDSDG": "6.407697"
},
{
"date": "2017-01-13",
"USDARS": "15.839041",
"USDCLP": "659.200012",
"USDSDG": "6.407704"
},
{
"date": "2017-01-14",
"USDARS": "15.839041",
"USDCLP": "659.200012",
"USDSDG": "6.407704"
}
]
}
How do I read it using Alamofire in swift 3.0
Below is what actually I'm trying to parse above JSON data via url.
Alamofire.request("myurl") .responseJSON { response in
print("In Alamofire")
if let arr = response.result.value as? [String:AnyObject]
{
if let arr = response.result.value as? [NSDictionary]
{
let val1 = (arr["main"]["USDARS"] as? String)
print(val1)
//It does not print any thing.
}
}
}
Please help me. I'm new to it.
Top level json is [String:Any] and main is an array i.e. [[String:String]]
Alamofire.request("myurl") .responseJSON { response in
if let result = response.result.value as? [String:Any],
let main = result["main"] as? [[String:String]]{
// main[0]["USDARS"] or use main.first?["USDARS"] for first index or loop through array
for obj in main{
print(obj["USDARS"])
print(obj["date"])
}
}
}
You should use SwiftyJson, which is a library for json parsing, very usefull with Alamofire
In your case you can do something like this with swiftyJson :
//Array & Dictionary
var jsonArray: JSON = [
"main": ["date": "2017-01-11", "USDARS": "15.8302"]
]
let dateString = jsonArray["main"][0]["date"].string
print(dateString) = "2017-01-11"
#IBAction func btnget(_ sender: UIButton) {
let urlpath : String = "http://202.131.123.211/UdgamApi_v4/App_Services/UdgamService.asmx/GetAllTeacherData?StudentId=2011111"
let url = URL(string: urlpath)
var urlrequest = URLRequest(url: url!)
urlrequest.httpMethod = "GET"
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let task = session.dataTask(with: urlrequest) { (data, response, error) in
do {
guard let getResponseDic = try JSONSerialization.jsonObject(with: data!, options: []) as? [String: AnyObject] else {
print("error trying to convert data to JSON")
return
}
// now we have the todo, let's just print it to prove we can access it
print(getResponseDic as NSDictionary)
let dic = getResponseDic as NSDictionary
let msg = dic.object(forKey: "message")
print(dic)
//let arrObj = dic.object(forKey: "teacherDetail") as! NSArray
//print(arrObj)
//let arr = dic.value(forKey: "TeacherName")as! NSArray
print(((dic.value(forKey: "teacherDetail") as! NSArray).object(at: 0) as! NSDictionary).value(forKey: "TeacherName") as! String)
// the todo object is a dictionary
// so we just access the title using the "title" key
// so check for a title and print it if we have one
// print("The title is: " + todoTitle)
} catch {
print("error trying to convert data to JSON")
return
}
} task.resume()
}

swift Unescaped control character

I'm trying to get a json from a server and deserialize it, but I try probelas with unescaped control characters.
My code is as follows ...
let urlFinal = "http://000.0000.000.000:8080"
let jsonUrl = urlFinal
let session = NSURLSession.sharedSession()
let shotsUrl = NSURL(string: jsonUrl)
let task = session.dataTaskWithURL(shotsUrl!) {data, response, error in
guard data != nil else {
falha()
return
}
//let json = JSON(data: data!)
//print(json["ServicoCliente"][0]["id"])
do {
let jsonData = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers )
let J = jsonData as! NSDictionary
print(jsonData)
let us = J["ServicoCliente"]
print(us)
dispatch_async(dispatch_get_main_queue(),{
sucesso()
});
} catch _ {
falha()
}
}
task.resume()
and I also tried this using Alamofire 3.0:
Alamofire.request(.GET, "http://000.000.000.000/", parameters: nil)
.responseJSON { response in
debugPrint(response) // prints detailed description of all response properties
print(response.request) // original URL request
print(response.response) // URL response
print(response.data) // server data
print(response.result) // result of response serialization
if let JSON = response.result.value {
print("JSON: \(JSON)")
}
}
And get this error:
Unescaped control character around character 263
How can I remove characters without escape?
I use X-Code 7.3.1 and Swift 2.3
UPDATE:
Json
{"ServicoCliente":[{"id":"195","cliente":"247","enderecoFavoritos":"48","servicoProfissional":"194","ind_estado_cliente":"A","ind_estado_profissional":"","profissional_id":"240","profissional_nome":"PetMax","servicotipo_nome":"Petshop","servicosubtipo_nome":"Tosa ","dta_inc_alt":"2016-11-05 22:56:19.333","ind_finalizado":"N"}]}
To fix this, you must convert the data for string, remove characters and then convert to dataonly then deserialize
let urlFinal = "http://000.0000.000.000:8080"
let jsonUrl = urlFinal
let session = NSURLSession.sharedSession()
let shotsUrl = NSURL(string: jsonUrl)
let task = session.dataTaskWithURL(shotsUrl!) {data, response, error in
guard data != nil else {
falha()
return
}
var dataToString = String(data: data!, encoding: NSUTF8StringEncoding)
dataToString = stringByRemovingControlCharacters2(dataToString!)
let ndata = dataToString!.dataUsingEncoding(NSUTF8StringEncoding)
do {
let jsonData = try NSJSONSerialization.JSONObjectWithData(ndata!, options: NSJSONReadingOptions.MutableContainers )
let J = jsonData as! NSDictionary
print(jsonData)
let us = J["ServicoCliente"]
print(us)
dispatch_async(dispatch_get_main_queue(),{
sucesso()
});
} catch _ {
falha()
}
}
task.resume()
and add the function
func stringByRemovingControlCharacters2(string: String) -> String {
let controlChars = NSCharacterSet.controlCharacterSet()
var range = string.rangeOfCharacterFromSet(controlChars)
var mutable = string
while let removeRange = range {
mutable.removeRange(removeRange)
range = mutable.rangeOfCharacterFromSet(controlChars)
}
return mutable
}
Swift 5
func string(byRemovingControlCharacters inputString: String) -> String {
let controlChars = CharacterSet.controlCharacters
var range = (inputString as NSString).rangeOfCharacter(from: controlChars)
if range.location != NSNotFound {
var mutable = inputString
while range.location != NSNotFound {
if let subRange = Range<String.Index>(range, in: mutable) { mutable.removeSubrange(subRange) }
range = (mutable as NSString).rangeOfCharacter(from: controlChars)
}
return mutable
}
return inputString
}

Swift error in converting nsdata to NSDictionary

I'm trying to get JSON Array from a web service and I keep getting an error, and I spent much time on this but I can't figure it out.
http://ashishkakkad.com/2014/10/update-json-array-parsing-in-swift-langauage-ios-8-xcode-6-gm/
my Code
if let url=NSURL(string:"http://www.example.com/service/service.php?get=6"){
print(url)
if let allContactsData=NSData(contentsOfURL:url){
if let string1 = NSString(data: allContactsData, encoding: NSUTF8StringEncoding){
print(string1)
}
do{
if let allContacts: AnyObject = try NSJSONSerialization.JSONObjectWithData(allContactsData, options:NSJSONReadingOptions.MutableContainers) as! NSDictionary{
if let json = allContacts as? Array<NSObject> {
print(json)
for index in 0...json.count-1 {
let contact : NSObject? = json[index]
print(contact)
let collection = contact! as! Dictionary<String, AnyObject>
print(collection)
print(collection["title"])
let name : AnyObject? = collection["title"]
let cont : AnyObject? = collection["link"]
self.names.append(name as! String)
self.contacts.append(cont as! String)
}
}
print(self.names)
print(self.contacts)
}
} catch {
print("Dim background error")
}
}
the error I get on this line
if let allContacts: AnyObject = try
NSJSONSerialization.JSONObjectWithData(allContactsData,
options:NSJSONReadingOptions.MutableContainers) as! NSDictionary
You should be casting to [[String: AnyObject]] rather than NSDictionary. However, I admit that I'm not familiar with the approach you're attempting to use, I would do something more like this:
enum HTTPStatusCodes : Int {
case Ok = 200
case Created = 201
case BadRequest = 404
}
let request = NSMutableURLRequest(URL: NSURL(string: "http://www.example.com/service/service.php?get=6")!)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTaskWithRequest(request) { (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in
guard let testResponse = response as? NSHTTPURLResponse else {
print("bad \(response)")
return
}
guard let status = HTTPStatusCodes(rawValue: testResponse.statusCode) else {
print("derpped gain")
return
}
print(status)
switch status {
case .Created:
print("ehem")
case .BadRequest:
print("bad request")
case .Ok:
print("ok")
let headerFields = testResponse.allHeaderFields
guard let returnedData = data else {
print("no data was returned")
break
}
do {
// convert data to string
let jsonObject = try NSJSONSerialization.JSONObjectWithData(returnedData, options: .MutableLeaves) as! [[String:AnyObject]]
//print(jsonDict)
} catch let error {
print(error)
}
// update user interface
dispatch_sync(dispatch_get_main_queue()) {
print("update interface")
}
}
}
task.resume()

Resources