Extract Data out of JSON in swift - json

This question has been asked a hundred times, but the internet isn't helping, mostly because I am new to swift and programming, so my apologies in advance.
I am trying to extract some data out json.
Here is my code:
let request = NSMutableURLRequest(url:myUrl! as URL);
request.httpMethod = "POST";
let postString = "email=\(email)";
request.httpBody = postString.data(using: String.Encoding.utf8);
let task = URLSession.shared.dataTask(with: request as URLRequest){
data, response, error in
if error != nil {
print("error=\(error)")
return
}
var err: NSError?
do
{
let myJson = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
print(myJson)
let name = myJson["name"]
}
catch let error as NSError {
err = error
}
}
task.resume()
And here is the JSON out of print(myJson):
(
{
name = "TestTest";
}
)
But I am receiving an error for:
let name = myJson["name"]
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)

The first issue you have is this line:
let myJson = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
You specify that the data will be of type AnyObject. But it should really be an array of dictionaries. So, instead, you should specify:
let myJson = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as [[String:Any]]
Of course, that alone will not fix things since you have to extract items from the array before you can use dictionary notation to get at the "name" value. So, you'd have to do something like this, after that:
let row = myJson[0]
let name = row["name"]

Related

dealing with nested json array swift

I am trying to convert some json data which i receive from a get request into a usable array or something like this
the json data i recieve looks like this
{
"elementlist":{
"Ready Position":{
"Neutral Grip":["1,2,3,4,5"],"
Back Straight (Concave ir Convex?)":["1,2,3,4,5"],"
Body Low & Feet a little more than sholder width apart":["1,2,3,4,5"],"
Weight on Balls of Feet":["1,2,3,4,5"],"
Head Up":["1,2,3,4,5"],"
Sholder Blades Close":["1,2,3,4,5"],"
Eyes Drilled":["1,2,3,4,5"]
},
"Split Step":{"
Ready Position Conforms":["Yes,No"],"
Body Position Low":["1,2,3,4,5"],"
Legs Loaded/Prepared":["1,2,3,4,5"]
}
}
}
this is the swift i am using
let playerAPIurl = "http://linkcoachuat.herokuapp.com/api/v1/session/element?organisation=5&group=green&sport=tennis"
var request = URLRequest(url: URL(string: playerAPIurl)!)
request.httpMethod = "GET"
let configuration = URLSessionConfiguration.default
let session = URLSession(configuration: configuration, delegate: nil, delegateQueue: OperationQueue.main)
let task = session.dataTask(with: request) { (data, response, error) in
if error != nil {
print("ERROR")
}
else{
do{
print("hello")
let myJson = try JSONSerialization.jsonObject(with: data!, options: []) as? [String: Any]
// Convert myJson into array here
print(myJson)
}
catch
{
}
}}
What i would like to be able to do is get an array of the names of the nested arrays so elementarray = ["Ready Position","Split Step"] and then be able to access the arrays by saying myJson[elementarray[0]] or something similar
im a bit of a swift noob so any help is appreciated please try and explain the answers so they are easily understood
thank you for any help
You can try to downcast that json same way you've already made:
let myJson = try JSONSerialization.jsonObject(with: data!, options: []) as? [String: Any]
//creating the new array of additional elements
let elementArray: [[String: Any]] = []
//making myJson parsing for additional items
if let readyPosition = myJson?["Ready Position"] as? [String: Any] {
elementArray.append(readyPosition)
}
if let splitStep = myJson?["Split Step"] as? [String: Any] {
elementArray.append(splitStep)
}
make print(elementArray) to be sure that all was parsed correctly.
Honestly, I prefer to use objects (custom classes or structs) to store values and have an ability to make related instances or values, but up to you

HTTP Request GET JSON and read data

i have a problem by a code of me in swift. I do a request to webserver by httpMethod POST. This request is ok. I get a response and data inside the data value. The data looks like JSON
{"pushValues": {"devicePushGlobal":"1","devicePushNewProducts":"1","devicePushNewOffer":"1"}}
Then I will load this response data to set buttons based on the response data. But i fail to write this code. Can someone help me please? :)
Error Code
Cannot invoke 'jsonObject' with an argument list of type '(with: NSString)'
// i tested with other options but i always fail :-(
I comment the error in the code ....
let url = "https://URL.php"
let request = NSMutableURLRequest(url: NSURL(string: url)! as URL)
let bodyData = "token=" + (dts)
request.httpMethod = "POST"
request.httpBody = bodyData.data(using: String.Encoding.utf8);
NSURLConnection.sendAsynchronousRequest(request as URLRequest, queue: OperationQueue.main) {
(response, data, error) in
// here i get the result of
// {"pushValues": {"devicePushGlobal":"1","devicePushNewProducts":"1","devicePushNewOffer":"1"}}
var str = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
var names = [String]()
// here i will get each value of pushValues to add to the array names
do {
if let data = str,
// ... and here is the error code by xcode ::: ==> Cannot invoke 'jsonObject' with an argument list of type '(with: NSString)'
// i tested with other options but i always fail :-(
let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
let blogs = json["pushValues"] as? [[String: Any]] {
for blog in blogs {
if let name = blog["devicePushGlobal"] as? String {
print(name)
names.append(name)
}
}
}
} catch {
print("Error deserializing JSON: \(error)")
}
// names array is empty
print(names)
}
Thank you for your help
You shouldn't decode the JSON response into an NSString using var str = NSString(data: data!, encoding: String.Encoding.utf8.rawValue). JSONSerialization.jsonObject() expects a Data object as an input argument, so just safely unwrap the optional data variable and use that as the input argument:
if let responesData = data, let json = try JSONSerialization.jsonObject(with: responseData) as? [String: Any], let blogs = json["pushValues"] as? [String: Any]
The full code using native Swift types:
...
let request = URLRequest(url: URL(string: url)!)
...
URLSession.shared.dataTask(with: request, completionHandler: {
(response, data, error) in
var names = [String]()
do {
if let responseData = data, let json = try JSONSerialization.jsonObject(with: responseData) as? [String: Any], let blogs = json["pushValues"] as? [String: Any]{
if let name = blog["devicePushGlobal"] as? Int {
print(name)
names.append(name)
}
if let newProducts = blog["devicePushNewProducts"] as? Int{}
if let newOffers = blog["devicePushNewOffers"] as? Int{}
}
} catch {
print("Error deserializing JSON: \(error)")
}
// names array is empty
print(names)
}).resume()

How can you properly convert Swift dictionaries to json and make post requests?

This is making post requests, but it is treating the json as a string, which shows up on the server as (stuff): ''. I don't know how to fix it. (When I used python to implement this, it was perfect.)
let json: [String: Any] = ["id": 1, "checksum": "hey"]
let jsonData = try? JSONSerialization.data(withJSONObject: json)
/*print(jsonData!)
let parsedData = try? JSONSerialization.jsonObject(with: jsonData!, options: [])
print(parsedData!)*/
//print(parsedData)
// create post request
let url = URL(string: "http://10.240.81.23:3000/updateProfile")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
// insert json data to the request
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "No data")
return
}
let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
if let responseJSON = responseJSON as? [String: Any] {
print(responseJSON)
}
}
task.resume()
Consider using Alamofire for networking, it is amazingly easy to use and works great. Also SwiftyJSON that makes JSON parsing and manipulation really easy and optional-safe.
You can use Carthage to install those two frameworks easily.

How to parse JSON data in Swift 3? [duplicate]

This question already has answers here:
Correctly Parsing JSON in Swift 3
(10 answers)
Closed 5 years ago.
I need to get my GPS location from mySQL by PHP in Swift 3. I tried to write the code for get data but it still not work, could you advise me?
JSON Data from PHP:
[{"id":"3752","latitude":"11.2222","longitude":"111.2222","Speed":"0.000000","Volt":"3.97","Percent":"87.000000","Dates":"2017-03-07 22:53:32"}]
Swift 3 code:
import UIKit
//-------- import google map library --------//
import GoogleMaps
import GooglePlaces
class ViewController: UIViewController , GMSMapViewDelegate {
var placesClient: GMSPlacesClient!
override func viewDidLoad() {
super.viewDidLoad()
var abc : String = String()
//-------- Google key for ios --------//
GMSServices.provideAPIKey("XXXXXXXXXX")
GMSPlacesClient.provideAPIKey("XXXXXXXXX")
//--------set URL --------//
let myUrl = URL(string: "http://www.myweb/service.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
if error != nil
{
print("error=\(error)")
return
}
// You can print out response object
print("response = \(response)")
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parseJSON = json {
// Now we can access value of latiutde
let latitude= parseJSON["latitude"] as? String //<---- Here , which i need latitude value
print("latitude = \(latitude)")
}
} catch {
print(error)
}
}
task.resume()
}
I tried to write the code but it show the errors on debug output
let responseString = String(data: data, encoding: .utf8 )
let str = String(data: data, encoding: .utf8 )
let data2 = str?.data(using: String.Encoding.utf8, allowLossyConversion: false)!
do {
let json = try JSONSerialization.jsonObject(with: data2!, options: []) as! [String: AnyObject]
if let names = json["latitude"] as? [String] {
print(names)
}
} catch let error as NSError {
print("Failed to load: \(error.localizedDescription)")
}
}
Error message
Could not cast value of type '__NSSingleObjectArrayI' (0x1065fad60) to
'NSDictionary' (0x1065fb288).
Try casting the json object to a Swift representation directly for a more 'Swifty' access of the underlying data. So you don't need to fuss around with NSNumber etc.
guard let json = JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [[String: String]] else { return }
guard json.count > 0 else { return }
guard let lattitude = json[0]["lattitude"] else { return }
print("Lattitude received: \(lattitude)")
If you are not sure you'll have a [String: String] object array, you can replace it with a [String: Any] in the cast, then all you need to do is check the type with an optional cast in reading the lattitude. You could add a chained optional then checking for isEmpty to check whether its the lattitude value you want or something went wrong.
I would also advice to pretty much never use ! in your code, try to rely more on optional chaining and guard statements.
Guard statement introduction
Note: a single line guard statement isn't very verbose and might make it very difficult to debug your application. Consider throwing errors or some more debug printing in the body of the guard statement.

How do I get a specific value from returned json in Swift 3.0?

I am trying to get a value from json in Swift. I have added an image of the data tree. My previous attempts have not worked. Below is code which prints the full json object which is what I don't want.
json tree image
import PlaygroundSupport
import UIKit
let url = URL(string: "https://api.data.gov.sg/v1/transport/taxi-availability")
var request = URLRequest(url: url!);
request.addValue("xxxx", forHTTPHeaderField: "api-key")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard error == nil else {
print(error)
return
}
guard let data = data else {
print("Data is empty")
return
}
let json = try! JSONSerialization.jsonObject(with: data, options: [])
//print(json)
}//end
//["features"]??[0]?
task.resume()
PlaygroundPage.current.needsIndefiniteExecution = true
You just need to do something with the json you've been vended:
let task = URLSession ... { data, response, error in
let json = JSONSerialization.jsonObject(...)
if let json = json as? [String: Any] {
// now you have a top-level json dictionary
for key, value in json {
print("json[\"\(key\")] = \(value)")
}
}
}
I didn't verify the following code but it should work for the son tree you provided. (disclaimer: might have some errors but its mostly correct)
if let json = (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String:Any]
, let features = json["features"] as? [Any]
, let firstFeature = features[0] as? [String:Any]
, let properties = firstFeature["properties"] as? [String:Any]
, let taxiCount = properties["taxi_count"] as? Int
{
print(taxiCount)
}
If Json is dictionary
let json = try! JSONSerialization.jsonObject(with: data, options: [])
let jsonDict = json as? NSDictionary
//if you have a key name
let name = jsonDict["name"] as? String
//and so on
//if you have a array in your dictionary
let likes = jsonDict["likes"] as? NSArray
let numberOfLikes = likes.count
for eachLike in likes {
let likerName = eachLike["liker_name"] as? String
}