Parsing JSON with SwiftyJSON - ios

I am working on a project and my JSON file I am getting from the website does not have any (key) for me to start my parsing from. So, when I use the line in the code , let userInfo = swiftyJSON[].arrayValue I will get all the information from the JSON file. My problem is that I need to parse it further so I can fill a UITableView and I cant seem to parse it to be more specific.
This is the code from my JSON
let externalURL = "http://jsonplaceholder.typicode.com/users"
func getJSON(){
let url = URL(string: externalURL)
let request = NSURLRequest(url: url! as URL)
let session = URLSession(configuration:URLSessionConfiguration.default)
let task = session.dataTask(with: request as URLRequest) {(data, response, error) -> Void in
if error == nil {
let swiftyJSON = JSON(data: data!)
let userInfo = swiftyJSON[].arrayValue
print(userInfo)
}
else{
print("There was an error")
}
}
task.resume()
}

A starting point:
let swiftyJSON = JSON(data: data!)
if let userInfo = swiftyJSON.array {
for user in userInfo {
print(user["name"].string, user["email"].string, user["phone"].string)
if let address = user["address"].dictionary {
print(address["city"]?.string)
}
}
}
All printed values are optionals.

Related

How to Decode Apple App Attestation Statement?

I'm trying to perform the Firebase App Check validation using REST APIs since it's the only way when developing App Clips as they dont' support sockets. I'm trying to follow Firebase docs. All I'm having trouble with is the decoding of the App Attestation Statement.
So far I've been able to extract the device keyId, make Firebase send me a challenge to be sent to Apple so they can provide me an App Attest Statement using DCAppAttestService.shared.attestKey method.
Swift:
private let dcAppAttestService = DCAppAttestService.shared
private var deviceKeyId = ""
private func generateAppAttestKey() {
// The generateKey method returns an ID associated with the key. The key itself is stored in the Secure Enclave
dcAppAttestService.generateKey(completionHandler: { [self] keyId, error in
guard let keyId = keyId else {
print("key generate failed: \(String(describing: error))")
return
}
deviceKeyId = keyId
print("Key ID: \(deviceKeyId.toBase64())")
})
}
func requestAppAttestChallenge() {
guard let url = URL(string: "\(PROJECT_PREFIX_BETA):generateAppAttestChallenge?key=\(FIREBASE_API_KEY)") else {
return
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
let task = URLSession.shared.dataTask(with: request) { [self] data, response, error in
guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else {
return
}
guard let data = data, error == nil else {
return
}
let response = try? JSONDecoder().decode(AppAttestChallenge.self, from: data)
if let response = response {
let challenge = response.challenge
print("Response app check challenge: \(challenge)")
print("Response app check keyID: \(deviceKeyId)")
let hash = Data(SHA256.hash(data: Data(base64Encoded: challenge)!))
dcAppAttestService.attestKey(deviceKeyId, clientDataHash: hash, completionHandler: {attestationObj, errorAttest in
let string = String(decoding: attestationObj!, as: UTF8.self)
print("Attestation Object: \(string)")
})
}
}
task.resume()
}
I tried to send the attestation object to Firebase after converting it in a String, although I wasn't able to properly format the String. I see from Apple docs here the format of the attestation, but it isn't really a JSON so I don't know how to handle it. I was trying to send it to Firebase like this:
func exchangeAppAttestAttestation(appAttestation : String, challenge : String) {
guard let url = URL(string: "\(PROJECT_PREFIX_BETA):exchangeAppAttestAttestation?key=\(FIREBASE_API_KEY)") else {
return
}
let requestBody = ExchangeAttestChallenge(attestationStatement: appAttestation.toBase64(), challenge: challenge, keyID: deviceKeyId)
let jsonData = try! JSONEncoder().encode(requestBody)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request) {data, response, error in
guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else {
print("Exchange App Attestation \(String(describing: response))")
return
}
guard let data = data, error == nil else {
return
}
print("Exchange App Attestation: \(data)")
}
task.resume()
}

URLSession datatask accessing older version of website?

I am using URLSession to scrape JSON data from my website. My code was throwing various errors relating to casting types, so I added some print statements to my code and found that this function is for some reason accessing an older version of my site. I have since updated the website's data, and verified that the new data is displaying properly both through visiting the website myself and using Rested. However, the print statements in the code below yield old data. The code does not read data from the disk so I am not sure why this is happening.
I have removed the website's link from my code for privacy purposes, but otherwise the function can be found below.
func websiteToDisk() {
let config = URLSessionConfiguration.default
config.waitsForConnectivity = true
let defaultSession = URLSession(configuration: config)
let url = URL(string: someURL)
let task = defaultSession.dataTask(with: url!) { data, response, error in
do {
print("Getting information from website")
if let error = error {
print(error.localizedDescription)
} else if let data = data,
let response = response as? HTTPURLResponse,
response.statusCode == 200 {
//do {
let jsonDecoder = JSONDecoder()
print("about to dcode")
let decodedData = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]//try jsonDecoder.decode([String: [String]].self, from: data)
print(decodedData)
print("accessing dictionary")
print(decodedData!["busLoops"])
let toWrite = decodedData!["busLoops"] as! [String]
let documentDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let busLoopsURL = documentDirectoryURL.appendingPathComponent("busLoops").appendingPathExtension("json")
let jsonEncoder = JSONEncoder()
let jsonData = try jsonEncoder.encode(toWrite)
try jsonData.write(to: busLoopsURL)
//} catch { print(error)}
}
}
catch { print(error)}
}
task.resume()
}
Try ignore local cache data
guard let url = URL(string: "http://....") else{
return
}
let request = NSMutableURLRequest(url: url)
request.cachePolicy = .reloadIgnoringCacheData
let task = URLSession.shared.dataTask(with: request as URLRequest) { (data, resp, error) in
}
task.resume()

Getting directions between two points in google maps iOS SDK

I have the following code to get the path between two points in Google maps iOS SDK. However, I am not receiving any data back or any errors even.
let url = URL(string: "http://maps.googleapis.com/maps/api/directions/json?origin=\(latitude),\(longitude)&destination=\(finallat),\(finallong)&key=**************")
URLSession.shared.dataTask(with: url!) { (data:Data?, response:URLResponse?, error:Error?) in
if let data = data {
do {
// Convert the data to JSON
let jsonSerialized = try JSONSerialization.jsonObject(with: data, options: []) as? [String : Any]
if let json = jsonSerialized, let url = json["url"], let explanation = json["explanation"] {
print(url)
print(explanation)
}
} catch let error as NSError {
print(error.localizedDescription)
}
} else if let error = error {
print(error.localizedDescription)
}
}
You don't do anything with the dataTask so it isn't actually being called. You need to call resume().
let url = URL(string: "http://maps.googleapis.com/maps/api/directions/json?origin=\(latitude),\(longitude)&destination=\(finallat),\(finallong)&key=**************")
let task = URLSession.shared.dataTask(with: url!) { (data:Data?, response:URLResponse?, error:Error?) in
if let data = data {
do {
// Convert the data to JSON
let jsonSerialized = try JSONSerialization.jsonObject(with: data, options: []) as? [String : Any]
if let json = jsonSerialized, let url = json["url"], let explanation = json["explanation"] {
print(url)
print(explanation)
}
} catch let error as NSError {
print(error.localizedDescription)
}
} else if let error = error {
print(error.localizedDescription)
}
}
task.resume()

How to parse Json object in swift 3

Hi my question is related to json object. i have this link "http://ip-api.com/json" and this link gives the details of your IP Address. i only need to print IP Address from this json file in swift 3. i am very new might be my question is basic but i need some help to sort out my project. so for i have done like below.
let requestURL: NSURL = NSURL(string: "http://ip-api.com/json")!
let urlRequest: NSMutableURLRequest = NSMutableURLRequest(url: requestURL as URL)
let session = URLSession.shared
let task = session.dataTask(with: urlRequest as URLRequest) {
(data, response, error) -> Void in
let httpResponse = response as! HTTPURLResponse
let statusCode = httpResponse.statusCode
if (statusCode == 200) {
print("Everyone is fine, file downloaded successfully.")
do{
let json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! [String:AnyObject]
if let stations = json["city"] as? [[String: AnyObject]] {
for station in stations {
if let name = station["regionName"] as? String {
self.names.append(name)
print("this is query\(name)")
}
else{
print ("no ip address is found")
}
}
}
}
catch {
print("Error with Json: \(error)")
}
}
}
task.resume()
many thanks in advance.
The IP address is the value for key query on the top level of the JSON
let json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! [String:Any]
if let query = json["query"] as? String {
print(query)
}
In Swift 3 the type of a JSON dictionary is [String:Any]
PS: You don't need a URL request for this task, pass the URL directly and use the native structs URL (and URLRequest)
let requestURL = URL(string: "http://ip-api.com/json")!
...
let task = session.dataTask(with: requestURL) {

Parse JSON response with SwiftyJSON without crash

My iOS app is getting JSON response from server
let myURL = NSURL(string: SERVER_URL);
let request = NSMutableURLRequest(URL:myURL!);
request.HTTPMethod = "POST";
let postString = ""
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding);
let task = NSURLSession.sharedSession().dataTaskWithRequest(request)
{
data, response, error in
if error != nil {
print("error=\(error)")
return
}
dispatch_async(dispatch_get_main_queue(),{
var json = JSON(data: data!)
let someInt = json["someInt"].int
let message = json["message"].stringValue
Sometimes server is down or there may be errors in JSON so there will be no such values (message, someInt) and I want to handle it without app crash - what can I do?
With SwiftyJSON, non-optional getters end with Value, and optional getters don't.
So to test if the value is here you can use optional binding with if let:
if let someInt = json["someInt"].int,
message = json["message"].string {
// someInt and message are available here
} else {
// someInt and message are not available
}
Or with guard:
guard let someInt = json["someInt"].int,
message = json["message"].string else {
// error, someInt and message are not available
return
}
// someInt and message are available here
Very simple, probably you already know it, you could protect your code with:
if let someInt = json["someInt"].int {
// do whatever you want with someInt
}
if let message = json["message"].string {
// do whatever you want with message
}
Try this approach:
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if let data = data,
jsonString = NSString(data: data, encoding: NSUTF8StringEncoding)
where error == nil {
var json = JSON(data: data!)
// use some protection as explained before..
} else {
print("error=\(error!.localizedDescription)")
}
}
task.resume()
Let me post my answer too =)
first of all you can implement small extension for failure JSON initializer:
extension JSON {
init?(_ data: NSData?) {
if let data = data {
self.init(data: data)
} else {
return nil
}
}
}
You may put it in global scope with SwiftyJSON imported and forget about forcing unwrap your data before use it in JSON. Same fail initializers can be written for other data types if you use them. Its only for a bit shorter and readable code in future. With many routes or in some cases, for example when you wait from json some single fields, this extension can make your code looks extremely easy and readable:
guard let singleMessage = JSON(data: data)?["message"].string else {return}
Then you need to check for nil in way that you need (in fact explained in previous answers). Probably you searching for fully valid data, so use if-let chain:
let myURL = NSURL(string: SERVER_URL);
let request = NSMutableURLRequest(URL:myURL!);
request.HTTPMethod = "POST";
let postString = ""
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding);
let task = NSURLSession.sharedSession().dataTaskWithRequest(request)
{
data, response, error in
if error != nil {
print("error=\(error)")
return
}
dispatch_async(dispatch_get_main_queue()) {
if let json = JSON(data: data),
someInt = json["someInt"].int,
message = json["message"].string,
// ...
{
// all data here, do what you want
} else {
print("error=\(error)")
return
}
}
}
The best would be to handle using try catch
request.HTTPBody = postdata.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request)
{
(data, response, error) in
dispatch_async(dispatch_get_main_queue(), {
var jsondata: AnyObject?
do
{
let jsondata = try NSJSONSerialization.JSONObjectWithData(data!, options: [])
print(jsondata)
// your code here
}
catch
{
print("Some Error Found")
}
})
}
task.resume()
If you encounter any error, you will receive a message in the console, thus preventing the application from crashing

Resources