I have a php file which create a JSON array. This the JSON output.
[{"employee_id":"1","employee_name":"Steve","employee_designation":"VP","employee_salary":"60000"},{"employee_id":"2","employee_name":"Robert","employee_designation":"Executive","employee_salary":"20000"},{"employee_id":"3","employee_name":"Luci","employee_designation":"Manager","employee_salary":"40000"},{"employee_id":"4","employee_name":"Joe","employee_designation":"Executive","employee_salary":"25000"},{"employee_id":"5","employee_name":"Julia","employee_designation":"Trainee","employee_salary":"10000"}]
I want to parse this array using swift in my app. So I used the following code to parse the JSON array
func jsonParser() {
let urlPath = "xxxxxxxxx/dbretrieve.php"
guard let endpoint = NSURL(string: urlPath) else { print("Error creating endpoint");return }
let request = NSMutableURLRequest(URL:endpoint)
NSURLSession.sharedSession().dataTaskWithRequest(request) { (data, response, error) -> Void in
do {
guard let dat = data else { throw JSONError.NoData }
guard let json = try NSJSONSerialization.JSONObjectWithData(dat, options:.AllowFragments) as? NSArray else { throw JSONError.ConversionFailed }
print(json)
} catch let error as JSONError {
print(error.rawValue)
} catch {
print(error)
}
}.resume()
}
but I get the following error
Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.}
What's the mistake I made?
I checked your json array. Its perfect.
The point where the issue might be serialization.
Depends on data you get in response
Try to disable debugging mode in PHP
Try below serialisation code
Sample Code:
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as! [String: AnyObject]
print(json)
} catch let error as NSError {
print("Failed to load: \(error.localizedDescription)")
}
Related
I was converting JSON from data when I received an error:
'NSInvalidArgumentException', reason: '*** +[NSJSONSerialization dataWithJSONObject:options:error:]: Invalid top-level type in JSON write'
The data was printed as expected, but the JSON wasn't. I think the code failed in the first line after the do statement.
do {
var str: String = "http://localhost:5000/requirements/\(Array.joined(separator: "_"))"
let url = URL(string: str)
URLSession.shared.dataTask(with: url!) { (data, response, error) in
guard let data = data else { return }
print(data)
do {
let json = try? JSONSerialization.data(withJSONObject: data)
print(json)
if let json = json {
print(json)
let decodedList = try? JSONDecoder().decode(List.self, from: json)
print(decodedList)
if let items = decodedList {
listToDisplay = items.itemsAsString.components(separatedBy: ",")
print(listToDisplay)
}
}
} catch let jsonErr {
print("Error serializing json", jsonErr)
}
}.resume()
return listToDisplay
}
I'm trying to work with JSON data returned from a service. The JSON is, according to JSON validators, valid and is very simple:
[{"ID":"SDS-T589863","TotalRisk":0.2458,"TotalScore":641.032}]
However trying to parse it in my Swift 4 code it is mysteriously (to me at least) invalid. Here's my attempt to parse it:
// make the request
let task = session.dataTask(with: urlRequest) {
(data, response, error) in
// check for any errors
guard error == nil else {
print(error!)
return
}
// make sure we got data
guard let responseData = data else {
print("Error: did not receive data")
return
}
// this is fine:
guard let ddd = String(bytes: responseData, encoding: String.Encoding.utf8) else {
print("can't")
return
}
print(ddd) // prints [{"ID":"SDS-T589863","TotalRisk":0.2458,"TotalScore":641.032}] happily
do {
// cannot serialize
guard let risk = try JSONSerialization.jsonObject(with: responseData, options: [JSONSerialization.ReadingOptions.allowFragments])
as? [String: Any]
else {
print("error trying to convert data to JSON")
return
}
print(risk)
} catch {
print("error trying to convert data to JSON")
return
}
}
task.resume()
}
Assuming that I have no control over the JSON object or the format in which it is returned to me, is there a way to tell what is wrong with the JSON and perhaps format the response so that it can be serialized correctly?
You should cast your data to the [[String: Any]] type because you have array in response.
You are trying to cast to [String: Any], but you have an array of [String: Any] because your response enclosed in [] brackets.
Example:
let risk = try JSONSerialization.jsonObject(with: responseData, options: [JSONSerialization.ReadingOptions.allowFragments]) as? [[String: Any]]
Or if you want to get just only one [String: Any] object from response you can write:
let risk = (try JSONSerialization.jsonObject(with: responseData, options: [JSONSerialization.ReadingOptions.allowFragments]) as? [[String: Any]])?.first
Or if your object can be an array or not an array (but it sounds a little bit strange) you could try to cast to several possible types.
The response type is array of json objects so you have to cast it to [[String: Any]]. Since you are using Swift 4, you can use Decodable type which maps the model to the response.
let task = URLSession().dataTask(with: urlRequest) { (data, response, error) in
// check for any errors
guard error == nil else {
print(error!)
return
}
// make sure we got data
guard let responseData = data else {
print("Error: did not receive data")
return
}
do {
let decoder = JSONDecoder()
let riskArray = try decoder.decode([Risk].self, from: responseData)
print(riskArray)
} catch {
print("error trying to convert data to Model")
print(error.localizedDescription)
}
}
task.resume()
You can define your Model struct like
struct Risk: Decodable {
let id: String
let totalRisk: Double
let totalScore: Double
enum CodingKeys: String, CodingKey {
case id = "ID"
case totalRisk = "TotalRisk"
case totalScore = "TotalScore"
}
}
You can read more about Decodable protocol here
I'm having this issue where I can't access values from JSON response,
the response is : {"result":[true]}
and when the JSON gets it with this code
do{
let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)
let result:String = json["result"]
print(result)
}catch {
print("Error with Json: \(error)")
}
I get an error, and the when I did the debug, I saw that json had the following
how json is stored
is there anyway to access the result from json ? it didn't work treating it as an array nor as dictionary
any ideas ?
thanks
result is not String, it's an Array of Bool (represented by the brackets).
Basically do not annotate types unless the compiler needs them.
Cast the JSON to the proper type and use Swift native collection types. It's also recommended to use optional bindings to avoid unexpected crashes.
do {
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments) as? [String:AnyObject],
result = json["result"] as? [Bool] where !result.isEmpty {
print(result[0])
}
} catch {
print("Error with Json: \(error)")
}
Try like this
do{
let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments) as! NSDictionary
let result = json["result"] as! NSArray
print(result)
let boole = result[0];
}catch {
print("Error with Json: \(error)")
}
I am currently trying to download, parse and print JSON from an URL.
So far I got to this point:
1) A class (JSONImport.swift), which handles my import:
var data = NSMutableData();
let url = NSURL(string:"http://headers.jsontest.com");
var session = NSURLSession.sharedSession();
var jsonError:NSError?;
var response : NSURLResponse?;
func startConnection(){
let task:NSURLSessionDataTask = session.dataTaskWithURL(url!, completionHandler:apiHandler)
task.resume();
self.apiHandler(data,response: response,error: jsonError);
}
func apiHandler(data:NSData?, response:NSURLResponse?, error:NSError?)
{
do{
let jsonData : NSDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary;
print(jsonData);
}
catch{
print("API error: \(error)");
}
}
My problem is, that the data in
do{
let jsonData : NSDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary;
print(jsonData);
}
remains empty.
When I debug,the connection starts successfully, with the given url as a parameter. But my jsonData variable doesn't get printed. Instead the catch block throws the error, stating that there is no data in my variable:
API error: Error Domain=NSCocoaErrorDomain Code=3840 "No value."
Can someone please help me with this?
What am I missing?
Thank you all very much in advance!
[Edited after switching from NSURL Connection to NSURLSession]
Here's an example on how to use NSURLSession with a very convenient "completion handler".
This function contains the network call and has the "completion handler" (a callback for when the data will be available):
func getDataFrom(urlString: String, completion: (data: NSData)->()) {
if let url = NSURL(string: urlString) {
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url) { (data, response, error) in
// print(response)
if let data = data {
completion(data: data)
} else {
print(error?.localizedDescription)
}
}
task.resume()
} else {
// URL is invalid
}
}
You can use it like this, inside a new function, with a "trailing closure":
func apiManager() {
getDataFrom("http://headers.jsontest.com") { (data) in
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: [])
if let jsonDict = json as? NSDictionary {
print(jsonDict)
} else {
// JSON data wasn't a dictionary
}
}
catch let error as NSError {
print("API error: \(error.debugDescription)")
}
}
}
Why am I unable to parse JSON from the HTTP response via the following code?
if let url = NSURL(string: "https://2ch.hk/b/threads.json") {
let task = NSURLSession.sharedSession().dataTaskWithURL(url) {
(data, response, error) in
var jsonError: NSError?
let jsonDict = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &jsonError) as [String: AnyObject]
if jsonError != nil {
return
}
// ...
}
task.resume()
}
Output
fatal error: unexpectedly found nil while unwrapping an Optional value
What am I doing wrong? How can I fix it?
Thanks in advance.
This is a bit late.... but I think you are trying to parse the error as well so add an else part and and the dictionary to be serialized will only be parsed if there is the data ... your code can be modified as follows
if let url = NSURL(string: "https://2ch.hk/b/threads.json") {
let task = NSURLSession.sharedSession().dataTaskWithURL(url) {
(data, response, error) in
if (jsonError != nil) {
return
} else {
var jsonError: NSError?
let jsonDict = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &jsonError) as [String: AnyObject]}
// ...
}
task.resume()
}