I'm running a NSJSONSerialization command with try catches but it is still failing when the command returns a nil. What am I doing incorrect with my try catches?
fatal error: unexpectedly found nil while unwrapping an Optional value happens at the line where z is set. Why doesn't the catch handle this?
func reachForWebsite(){
let url = NSURL(string: "https://myURL")
let task = NSURLSession.sharedSession().dataTaskWithURL(url!) {(data, response, error) in
do {
let z = try NSJSONSerialization.JSONObjectWithData(data!, options:[]) as! [NSObject: AnyObject]
} catch let myJSONError {
print(myJSONError)
}
}
task!.resume()
}
The do-try-catch process catches errors that are thrown, but is not a generalized exception handling process. As before, as a developer, you are still responsible for preventing exceptions from arising (e.g. the forced unwrapping of the optional NSData).
So, check to make sure data is not nil before proceeding. Likewise, don't use as! in the cast unless you are assured that the cast cannot fail. It is safer to guard against data being nil and perform an optional binding of the JSON to a dictionary:
let task = NSURLSession.sharedSession().dataTaskWithURL(url!) { data, response, error in
guard data != nil else {
print(error)
return
}
do {
if let z = try NSJSONSerialization.JSONObjectWithData(data!, options:[]) as? [String: AnyObject] {
// do something with z
}
} catch let parseError {
print(parseError)
}
}
task.resume()
You need to check the values of error and data before trying to give them to NSJSONSerialization to parse – data is probably nil, which is what triggers your crash.
Related
So I know how to parse JSON and retrieve a JSON from a URLRequest. What my objective is to remove this JSON file so I can manipulate it into different UIViewControllers. I have seen some stuff with completion handlers but I run into some issues, and I haven't fully understand. I feel like there is a simple answer, I am just being dumb.
How can I take this JSON outside the task and use it in other Swift files as a variable?
class ShuttleJson: UIViewController{
func getGenres(completionHandler: #escaping (_ genres: [String: Any]) -> ()) {
let urlstring = "_________"
let urlrequest = URLRequest(url: URL(string: urlstring)!)
let config = URLSessionConfiguration.default
let sessions = URLSession(configuration: config)
// request part
let task = sessions.dataTask(with: urlrequest) { (data, response, error) in
guard error == nil else {
print("error getting data")
print(error!)
return
}
guard let responseData = data else {
print("error, did not receive data")
return
}
do {
if let json = try JSONSerialization.jsonObject(with: responseData, options: []) as? [String: Any]{
//Something should happen here
}
print("no json sucks")
}
catch{
print("nah")
}
}
task.resume()
}
}
First of all remove the underscore and the parameter label from the completion handler. Both are useless
func getGenres(completionHandler: #escaping ([String: Any]) -> ()) {
Then replace the line
//Something should happen here
with
completionHandler(json)
and call the function
getGenres() { json in
print(json)
}
Notes:
The check guard let responseData = data else is redundant and it will never fail. If error is nil then data is guaranteed to have a value.
You should print the caught error rather than a meaningless literal string.
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)")
}
I am trying to write a method that scan the barcode then using http rest call to get some JSON data from a server. Alamofire doesn't work now and I tried many different ways.
Here is what I got now:
let getEndpoint: String = "45.55.63.218:8080/food?foodidentifier=\(code)"
let requestURL: NSURL = NSURL(string: getEndpoint)!
let urlRequest: NSMutableURLRequest = NSMutableURLRequest(URL: requestURL)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(urlRequest) {
(data, response, error) -> Void in
let httpResponse = response as! NSHTTPURLResponse
let statusCode = httpResponse.statusCode
if (statusCode == 200) {
print("Everyone is fine, file downloaded successfully.")
do{
//let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)
}catch {
print("Error with Json: \(error)")
}
}
}
task.resume()
I get an error message:
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb) on line: let httpResponse = response as! NSHTTPURLResponse
The problem is that the forced cast to NSHTTPURLResponse will fail if response was nil (for example, if there was some error that prevented the request from being issued successfully, as in this case where the URL string was missing the http:// scheme prefix; but this could happen for any of a variety of issues, so one must anticipate and handle network errors gracefully). When processing responses from network requests, one should studiously avoid forced unwrapping/casting unless you have first confirmed that the value is valid and non-nil.
I would suggest:
using guard statements to safely check for nil values;
check that data was not nil and that error was nil before bothering to check status codes;
So, that might yield:
let task = session.dataTaskWithRequest(urlRequest) { data, response, error in
guard data != nil && error == nil else {
print(error)
return
}
guard let httpResponse = response as? NSHTTPURLResponse where httpResponse.statusCode == 200 else {
print("status code not 200; \(response)")
return
}
print("Everyone is fine, file downloaded successfully.")
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: [])
print(json)
} catch let parseError {
print("Error with Json: \(parseError)")
}
}
task.resume()
i created a watchOS app that request a value from an API and show it on a label.
It is working perfectly in the simulator but when I execute it on my Apple Watch it crashes with the following error:
[ERROR] There is an unspecified error with the connection
fatal error: unexpectedly found nil while unwrapping an Optional value
The first error is generated by my code.
The code I wrote is:
func price_request() -> NSData? {
guard let url = NSURL(string: "https://api.xxxxx.com/xxx.php") else {
return nil
}
guard let data = NSData(contentsOfURL: url) else {
print("[ERROR] There is an unspecified error with the connection")
return nil
}
print("[CONNECTION] OK, data correctly downloaded")
return data
}
func json_parseData(data: NSData) -> NSDictionary? {
do {
let json: AnyObject = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as! Dictionary<String, AnyObject>
print("[JSON] OK!")
return (json as? NSDictionary)
} catch _ {
print("[ERROR] An error has happened with parsing of json data")
return nil
}
}
I tried also to add the App Transport Security bypass also if it is not needed because of a request to an HTTPS URL but it does not works.
Can you please help me?
Thank you
Try using NSURLSession to get data...
//declare data task
var task: URLSessionDataTask?
//setup the session
let url = URL(string:"https://url.here")!
let session = URLSession(configuration: URLSessionConfiguration.default)
task = session.dataTask(with: url){ (data, res, error) -> Void in
if let e = error {
print("dataTaskWithURL fail: \(e.localizedDescription)")
return
}
if let d = data {
//do something
}
}
task!.resume()
I'm trying to explore this new (for me) language, and I'm making an app that like many others retrieve some json data from a server.
in this function (from a tutorial I found) I get 4 errors, and I'm unable to fix it:
func json_parseData(data: NSData) -> NSDictionary? {
do {
let json: AnyObject = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers)
print("[JSON] OK!")
return (json as? NSDictionary)
}catch _ {
print("[ERROR] An error has happened with parsing of json data")
return nil
}
}
the first one is at the "try", xcode suggest me to fix it using "try;"
the others at the "catch" and are this others:
Braced block of statement is an unused closure
Type of expression is ambiguous without more context
Expected while in do-while-loop
please help me to understand
It seems that you are using Xcode 6.x and Swift 1.x where the do-try-catch syntax is not available (only Xcode 7 and Swift 2)
This code has equivalent behavior:
func json_parseData(data: NSData) -> NSDictionary? {
var error: NSError?
// passing the error as inout parameter
// so it can be mutated inside the function (like a pointer reference)
let json: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainerserror: &error)
if error == nil {
print("[JSON] OK!")
return (json as? NSDictionary)
}
print("[ERROR] An error has happened with parsing of json data")
return nil
}
Note: as of Xcode 7 beta 6 you can also use try? which returns nil if an error occurs.