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()
}
Related
i did read a lot about functions with completion-handler, but now i have a problem how to call this function (downloadJSON) in the correct way. Which parameters do i have to give in the function and handle the result-data (json) in my own class, where the function was called.
This is the code from David Tran. Hi makes wonderful tutorials, but in the code there is no call of this function.
let request: URLRequest
lazy var configuration: URLSessionConfiguration = URLSessionConfiguration.default
lazy var session: URLSession = URLSession(configuration: self.configuration)
typealias JSONHandler = (JSON?, HTTPURLResponse?, Error?) -> Void
func downloadJSON(completion: #escaping JSONHandler)
{
let dataTask = session.dataTask(with: self.request) { (data, response, error) in
// OFF THE MAIN THREAD
// Error: missing http response
guard let httpResponse = response as? HTTPURLResponse else {
let userInfo = [NSLocalizedDescriptionKey : NSLocalizedString("Missing HTTP Response", comment: "")]
let error = NSError(domain: DANetworkingErrorDomain, code: MissingHTTPResponseError, userInfo: userInfo)
completion(nil, nil, error as Error)
return
}
if data == nil {
if let error = error {
completion(nil, httpResponse, error)
}
} else {
switch httpResponse.statusCode {
case 200:
// OK parse JSON into Foundation objects (array, dictionary..)
do {
let json = try JSONSerialization.jsonObject(with: data!, options: []) as? [String : Any]
completion(json, httpResponse, nil)
} catch let error as NSError {
completion(nil, httpResponse, error)
}
default:
print("Received HTTP response code: \(httpResponse.statusCode) - was not handled in NetworkProcessing.swift")
}
}
}
dataTask.resume()
}
Let Xcode help you. Type downlo and press return. Xcode completes the function
Press return again and you get the parameters
You have to replace the placeholders with parameter names for example
downloadJSON { (json, response, error) in
if let error = error {
print(error)
} else if let json = json {
print(json)
}
}
Note:
There is a fatal type mismatch error in your code: The result of the JSONSerialization line is [String:Any] but the first parameter of the completion handler is JSON
I am receiving the error: Use of unresolved identifier 'json'
from this line: if let parseJSON = json {
This is the snippet of the code relevant to the error
let task = NSURLSession.sharedSession().dataTaskWithRequest(request){
data, response, error in
if error != nil {
print("error=\(error)")
return
}
do {
if let jsonResult = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSDictionary {
print(jsonResult)
}
} catch let error as NSError {
print(error.localizedDescription)
}
if let parseJSON = json {
var resultValue:String = parseJSON["status"] as String!;
print("Result: \(resultValue)")
if(resultValue=="Success")
{
//Login is sucessful
NSUserDefaults.standardUserDefaults().setBool(true,forKey:"isUserLoggedIn");
NSUserDefaults.standardUserDefaults().synchronize()
self.dismissViewControllerAnimated(true, completion: nil)
}
}
}
task.resume()
}
}
I reviewed this problem: Swift : Use of unresolved identifier 'json' but I do not know how I can fix my issue or where to put the variable of json
I think you meant to write if let parseJSON = jsonResult but anyways that is not gonna work either since the variables declared in the do are only visible at that scope. you need to move relevant code inside the do. You can assign the result of JSONSerialization directly to parsJSON.
You should also change this line var resultValue:String = parseJSON["status"] as String! to var resultValue:String = parseJSON["status"] as! String
Modify your code like this:
let task = NSURLSession.sharedSession().dataTaskWithRequest(request){
data, response, error in
if error != nil {
print("error=\(error)")
return
}
do {
if let parseJSON = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSDictionary {
print(parseJSON)
let resultValue:String = parseJSON["status"] as! String
print("Result: \(resultValue)")
if(resultValue=="Success")
{
//Login is sucessful
NSUserDefaults.standardUserDefaults().setBool(true,forKey:"isUserLoggedIn");
NSUserDefaults.standardUserDefaults().synchronize()
self.dismissViewControllerAnimated(true, completion: nil)
}
}
} catch let error as NSError {
print(error.localizedDescription)
}
}
task.resume()
}
}
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)")
}
}
}
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)")
}
#IBOutlet weak var weather: UILabel!
#IBOutlet weak var city: UITextField!
#IBAction func button(sender: AnyObject) {
let urlpath = "api.worldweatheronline.com/free/v2/weather.ashx?q=\(city.text)&format=json&num_of_days=5&key=c7fc4c9444ae2ddcee02a0893d5f0"
let url = NSURL(string: urlpath)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
self.weather.text="error"
}else{
var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
println(jsonResult)
}
})
task.resume()
}
I receive errors in the console when running the application. I am correctly serializing the data I believe but, I can not get the JSON serialized data to show up in an NSDictionary. I have tried to print the Dictionary to the console and it still just shows up as error. Please help me understand whats wrong here.
Try some thing like this.
func fetchWeatherData(latLong: String, completion: WeatherDataCompletionBlock) {
let baseUrl = NSURL(string: "http://api.worldweatheronline.com/free/v2/weather.ashx?q=\(city.text)&format=json&num_of_days=5&key=c7fc4c9444ae2ddcee02a0893d5f0")
let request = NSURLRequest(URL: baseUrl!)
println(request)
let task = session.dataTaskWithRequest(request) {[unowned self] data, response, error in
if error == nil {
var jsonError: NSError?
if (jsonError == nil) {
let weatherDictionary = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.AllowFragments, error: &jsonError) as NSDictionary
let data = WeatherData(weatherDictionary: weatherDictionary)
completion(data: data, error: nil)
} else {
completion(data: nil, error: jsonError)
}
} else {
completion(data: nil, error: error)
}
}
task.resume()
}