I am trying to print JSON data to the screen but whenever I run the application, the program crashes. I have searched stack overflow but cannot find my issue.
var url = NSURL(string: "https://alpha-api.app.net/stream/0/posts/stream/global")!
var requestURL = NSURLRequest(URL: url)
NSURLConnection.sendAsynchronousRequest(requestURL, queue: NSOperationQueue(), completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
var json = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as [NSMutableDictionary]
println(json)
println("Got data from \(requestURL.URL)")
})
A few things I would personally do, see if these will make it work better:
var request = NSMutableURLRequest(URL: passedURL)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {
(response, data, error) in
println(response)
println(data)
println(error)
if error == nil {
if let HTTPResponse = response as? NSHTTPURLResponse {
let statusCode = HTTPResponse.statusCode
if statusCode == 200 {
println("success")
}
}
}
}
If that doesn't work do these steps:
First, check if the link works. If it does, I'd just try printing the error, data and response to the logs before doing anything. If those are clear, try printing the data without turning it into JSON and see if it works.
Related
I'm trying to connect to a database from an iOS application written in Swift. I can't find a function that replaces all the others, which have been marked as deprecated in the latest iOS update (9.2?). Some of those functions are sendSynchronousRequest and sendAsynchronousRequest.
I want to read the data and response from the database. I'm using the following code:
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: {(response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in
let res = response as! NSHTTPURLResponse
if(res.statusCode >= 200 && res.statusCode < 300) {
let jsonData:NSDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
}
})
I'm getting an error at the first line:
Invalid conversion from throwing function of type '(NSURLResponse?, NSData?, NSError?) throws -> Void' to non-throwing function type '(NSURLResponse?, NSData?, NSError?) -> Void'
However, when I comment out the line in the if-statement (let jsonData:NSDictionary = try ...) the error disappears.
I know this function is deprecated; I can't find anything else.
How can I read the response from the AsynchronousRequest without errors?
You are missing the do/catch block
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) { (response, data, error) -> Void in
let res = response as! NSHTTPURLResponse
do {
if(res.statusCode >= 200 && res.statusCode < 300) {
let jsonData:NSDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
}
} catch {
}
}
But easier and better way in swift is this networking library: Alamofire
Example:
Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
.responseJSON { response in
print(response.request) // original URL request
print(response.response) // URL response
print(response.data) // server data
print(response.result) // result of response serialization
if let JSON = response.result.value {
print("JSON: \(JSON)")
}
}
I am new to iOS developing and need some help with JSON and what to be returning. I have the following function in my modal:
func loginRequest(username: String, password: String, completionHandler: ((NSURLResponse!, JSON, NSError?) -> Void)) {
var request : NSMutableURLRequest = NSMutableURLRequest()
request.URL = NSURL(string: ""correct post url"\(username)/\(password)")
request.HTTPMethod = "POST"
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:{ (response:NSURLResponse!, data: NSData!, error: NSError!) -> Void in
var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil
let httpResponse = response as? NSHTTPURLResponse
var json = JSON(data: data!)
println(json)
})
}
This does successfully return the JSON if I print it inside this function. However, the following code in my view controller yields no errors but fails to return the JSON at all.
#IBAction func signIn(sender: UIButton) {
modal.loginRequest("Test", password: "Pass") { (response, json, error) -> Void in
println(json)
println("Hello")
if (json != nil) {
Do parsing stuff
}
}
In my ViewController, json does not return nil, it doesn't return at all. The code prints in from my modal but does not show in the VC. How am I calling the function wrong?
Your function doesn't call the completion handler closure which is passed as param. If you want access the data however, you have to call the completionHandler closure. This is how your code should be:
func loginRequest(username: String, password: String, completionHandler: ((NSURLResponse!, JSON, NSError?) -> Void)) {
var request : NSMutableURLRequest = NSMutableURLRequest()
request.URL = NSURL(string: ""correct post url"\(username)/\(password)")
request.HTTPMethod = "POST"
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:{ (response:NSURLResponse!, data: NSData!, error: NSError!) -> Void in
var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil
let httpResponse = response as? NSHTTPURLResponse
var json = JSON(data: data!)
println(json)
// call the closure argument here, to pass the asynchrounsly retrieved vallues
// back to the caller of loginRequest
completionHandler(response, json, error)
})
}
I was reading the different ways to parse REST API calls in Swift and came across the following:
var url : String = "http://google.com?test=toto&test2=titi"
var request : NSMutableURLRequest = NSMutableURLRequest()
request.URL = NSURL(string: url)
request.HTTPMethod = "GET"
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:{ (response:NSURLResponse!, data: NSData!, error: NSError!) -> Void in
var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil
let jsonResult: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.MutableContainers, error: error) as? NSDictionary
if (jsonResult != nil) {
// process jsonResult
} else {
// couldn't load JSON, look at error
}
})
The one line that makes no sense to me is var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil. We already captured our NSError parameter and stored it in a variable called error, and now we're overwriting that and making it nil in our first line in the closure? Or if somehow Swift then performs a downcast of the error from type NSError! to AutoreleasingUnsafeMutablePointer<NSError?>, then can someone explain how that happens?
Thanks!
AutoreleasingUnsafeMutablePointer is the equivalent to NSError** in Objective-C, which is used in methods as an inout expression. The syntax looks very strange.
The most reliable way is to consider both errors and define a second error variable. As GET is the default HTTP method of NSURLRequest, an immutable request is sufficient.
let url = "http://google.com?test=toto&test2=titi"
let request = NSURLRequest(URL: NSURL(string: url)!)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:{ (response:NSURLResponse!, data: NSData!, error: NSError!) -> Void in
if error != nil {
// handle NSURLConnection error
} else {
var jsonError : NSError?
if let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.MutableContainers, error: &jsonError) as? NSDictionary {
// process jsonResult
} else {
// couldn't load JSON, look at jsonError
}
}
})
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let url = NSURL(string: "https://api.forecast.io/forecast/MYKEYHERE/")
let session = NSURLSession.sharedSession()
let task: NSURLSessionDownloadTask = session.downloadTaskWithURL(url!, completionHandler: { (location: NSURL!, response: NSURLResponse!, error: NSError!) -> Void in
if error == nil {
let data = NSData(contentsOfURL: location)
let json: NSDictionary = NSJSONSerialization.JSONObjectWithData(data!, options: nil, error: nil) as! NSDictionary!
println(json)
}
})
task.resume()
}
This is code for a download task to a weather API. Just wondering why I am getting the error:
Thread 6: EXC_BAD_INSTRUCTION(code=EXC_1386_INVOP, subcode=0x0).
Thanks a lot.
You're getting this error because the response is not JSON (or the JSON is not a dictionary). So, when parsing the JSON, use optional binding to gracefully handle nil or non-dictionary errors, perhaps examining the body of response if it fails, e.g.:
let task = session.downloadTaskWithURL(url!) { location, response, error in
if error == nil {
let data = NSData(contentsOfURL: location)
var error: NSError?
if let json = NSJSONSerialization.JSONObjectWithData(data!, options: nil, error: &error) as? NSDictionary {
println("json = \(json)")
} else {
println("error = \(error)")
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
println("not json; responseString = \(responseString)")
println(response)
}
}
}
task.resume()
Also, note, when using JSONObjectWithData, you not only want to gracefully check for an error, but you generally want to use the error parameter, too, as noted above.
BTW, make sure you include the latitude and longitude in the URL as described in the forecast.io API documentation, or else you'll get a non-JSON error response. Even if you fix the URL to avoid this error, you should still implement some graceful handling of errors, like above, or else your app might crash whenever there are any server issues.
No matter what I do it seems I'm unsuccessful in sending requests. Given the below sample code I copied word for word just to see the results. Yet nothing happens, I'm really confused and need help figuring out why i can send requests fine with objective c but no matter how many variations NSURLRequest NSURLSession I try it never works on swift.
var url : String = "http://google.com?test=toto&test2=titi"
var request : NSMutableURLRequest = NSMutableURLRequest()
request.URL = NSURL(string: url)
request.HTTPMethod = "GET"
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(),
completionHandler:{ (response:NSURLResponse!, data: NSData!, error: NSError!) -> Void in
var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil
let jsonResult: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.MutableContainers, error: error) as? NSDictionary
if (jsonResult != nil) {
println("help me")
// process jsonResult
} else {
println("hmmm")
// couldn't load JSON, look at error
}
})
DO NOT test network asynchronous requests on a commande line project.
The execution flow will stop before the asynchronousRequest terminates... You would need to add a run loop for that. Check out this link for an example.
You should take the habit to print out everything you get from a request, to understand what is going on. You can comment out everything after you are sure the request is working as expected.
var url : String = "http://google.com?test=toto&test2=titi"
var request : NSMutableURLRequest = NSMutableURLRequest()
request.URL = NSURL(string: url)
request.HTTPMethod = "GET"
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(),
completionHandler:{ (response:NSURLResponse!, data: NSData!, error: NSError!) -> Void in
println("OK")
var strData = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Body: \(strData)\n\n")
println("Response: \(response)")
var err:NSError?
let jsonResult: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.MutableContainers, error: &err) as? NSDictionary
if (jsonResult != nil) {
println("jsonresult : \(jsonResult)")
// process jsonResult
} else {
println(err.debugDescription)
// couldn't load JSON, look at error
}
})
I added a line to print the NSData converted to a NSString.
Here the data is nil.
That explains the JSON parsing error.
Also, the way you create the error is not right. Check out my version to correct it.
You aren't checking for the results of your various variables. If you're trying to diagnose problems, you have to look at each critical variable. For example, first check to see if the request succeeded and if not, quit immediately. Otherwise, try parsing the JSON, showing the resulting object if successful, but showing the parsing error on failure. If the JSON parsing fails (as it will with this URL), you might even look at the string representation of the returned data.
FYI, the handling of the NSError object with NSJSONSerialization is also incorrect. It should look like:
var parsingError: NSError?
if let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &parsingError) as? NSDictionary {
// success, use `jsonResult`
} else {
// failure, look at `parsingError`
}
Putting that all together:
let url = "http://google.com?test=toto&test2=titi"
let request = NSMutableURLRequest(URL: NSURL(string: url)!)
request.HTTPMethod = "GET"
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue()) {
response, data, error in
if data == nil {
println("request error: \(error)")
return
}
var parsingError: NSError?
if let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &parsingError) as? NSDictionary {
println("json parsed: \(jsonResult)")
} else {
println("parsing error: \(parsingError)")
let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
println("data: \(responseString)")
}
}
This will, with this particular URL, fail, because the response is not JSON, but this will also show you the string representation of the response.