Swift AsynchronousRequest response cannot be read - ios

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)")
}
}

Related

Alamofire Completion Handler returning response + data

I have a function that includes a responseObject in it's completion handler. At the moment this returns the json body when I call it, along with any errors.
Some parts of the API I am using however, don't return any data in the response body, they just return a response (200, 404, etc...)
I was thinking about appending the response inside the empty json object that is getting returned, then realised that would be silly and it would probably be better if I returned the NSHTTPURLResponse as well, but everything I have found just explains how to return the responseObject along with the error...
This is the function that returns the completion handler:
func makePostRequest(url : String, params : AnyObject, completionHandler: (responseObject: NSHTTPURLResponse, JSON?, error: NSError?) -> ()) -> Request? {
println("params = \(params)")
return Alamofire.request(.POST, url, parameters: params as? [String : AnyObject], encoding: .JSON)
.responseJSON { (request, response, data, error) in completionHandler(
//This is wrong
response: response as? NSHTTPURLResponse,
responseObject:
{
println("Request is \(request)")
println("Response is \(response)")
println("Data is \(data)")
println("Error is \(error)")
//Append the response to this JSON object?
//
var json:JSON = [:]
if let anError = error
{
println(error)
}
else if let data: AnyObject = data
{
json = JSON(data)
}
//probably better to return the two...
//
return (response, json)
}(),
error: error
)
}
}
And this is how its used:
networking.makePostRequest(documentUrl, params: docParams) { response, json, error in
println("response is: \(response)")
println("document json: \(json)")
println("document error: \(error)")
}
I've added in the 'response' bits to all the bits of code, i'm sure this is possible? just not sure how to achieve it..
For anyone stuck trying to figure out how to return stuff this way, I solved it like this:
func makePostRequest(url : String, params : AnyObject, completionHandler: (httpResponse: NSHTTPURLResponse, responseObject:JSON?, error: NSError?) -> ()) -> Request? {
println("params = \(params)")
return Alamofire.request(.POST, url, parameters: params as? [String : AnyObject], encoding: .JSON)
.responseJSON { (request, response, data, error) in completionHandler(
//This is wrong
httpResponse: response!,
responseObject:
{
println("Request is \(request)")
println("Response is \(response)")
println("Data is \(data)")
println("Error is \(error)")
//Append the response to this JSON object?
//
var json:JSON = [:]
if let anError = error
{
println(error)
}
else if let data: AnyObject = data
{
json = JSON(data)
}
return json
}(),
error: error
)
}
}
and then calling it like this:
networking.makePostRequest(workDocumentUrl, params: params) { response, json, error in
if response.statusCode == 200{
//do something
}
println("json: \(json)")
println("error: \(error)")
}

How to return JSON in swift from HTTPPost

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)
})
}

What is the point of a nil AutoreleasingUnsafeMutablePointer in a Swift closure?

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
}
}
})

Issue Retrieving JSON Data from website

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.

Swift can't send URLRequest at all?

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.

Resources