New value is only available in sendAsynchronousRequest - Swift
sendAsynchronousRequest
is, as the name suggests, asynchronous. So your final println
runs before the request is complete. After the completion handler runs, the new data will be available for all readers (in or outside this handler).
NSURLConnection sendAsynchronousRequest can't get variable out of closure
This is calling asynchronous function that is using a completion handler block/closure. So, you need to employ the completion handler pattern in your own code. This consists of changing the method return type to Void
and adding a new completionHandler
closure that will be called when the asynchronous call is done:
func post(url: String, info: String, completionHandler: (NSString?, NSError?) -> ()) {
let URL = NSURL(string: url)!
let request = NSMutableURLRequest(URL:URL)
request.HTTPMethod = "POST"
let bodyData = info
request.HTTPBody = bodyData.dataUsingEncoding(NSUTF8StringEncoding);
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) { response, data, error in
guard data != nil else {
completionHandler(nil, error)
return
}
completionHandler(NSString(data: data!, encoding: NSUTF8StringEncoding), nil)
}
}
Or, since NSURLConnection
is now formally deprecated, it might be better to use NSURLSession
:
func post(url: String, info: String, completionHandler: (NSString?, NSError?) -> ()) -> NSURLSessionTask {
let URL = NSURL(string: url)!
let request = NSMutableURLRequest(URL:URL)
request.HTTPMethod = "POST"
let bodyData = info
request.HTTPBody = bodyData.dataUsingEncoding(NSUTF8StringEncoding);
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
dispatch_async(dispatch_get_main_queue()) {
guard data != nil else {
completionHandler(nil, error)
return
}
completionHandler(NSString(data: data!, encoding: NSUTF8StringEncoding), nil)
}
}
task.resume()
return task
}
And you call it like so:
post(url, info: info) { responseString, error in
guard responseString != nil else {
print(error)
return
}
// use responseString here
}
// but don't try to use response string here ... the above closure will be called
// asynchronously (i.e. later)
Note, to keep this simple, I've employed the trailing closure syntax (see Trailing Closure section of The Swift Programming Language: Closures), but hopefully it illustrates the idea: You cannot immediately return the result of an asynchronous method, so provide a completion handler closure that will be called when the asynchronous method is done.
Cannot invoke 'sendAsynchronousRequest' in Swift 2 with an argument list
With Swift 1.2 and Xcode 6.3, the signature of sendAsynchronousRequest:queue:completionHandler:
is:
class func sendAsynchronousRequest(request: NSURLRequest,
queue: NSOperationQueue!,
completionHandler handler: (NSURLResponse!, NSData!, NSError!) -> Void)
With Swift 2 and Xcode 7 beta, however, the signature of sendAsynchronousRequest:queue:completionHandler:
has changed and is now:
// Note the non optionals, optionals and implicitly unwrapped optionals differences
class func sendAsynchronousRequest(request: NSURLRequest,
queue: NSOperationQueue,
completionHandler handler: (NSURLResponse?, NSData?, NSError?) -> Void)
As a consequence, turning to Swift 2 and Xcode 7 beta, you will have to change your completionHandler
parameter implementation and ensure that your queue
parameter is a non optional.
sendAsynchronousRequest was deprecated in iOS 9, How to alter code to fix
Use NSURLSession
instead like below,
For Objective-C
NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithURL:[NSURL URLWithString:"YOUR URL"]
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
// handle response
}] resume];
For Swift,
var request = NSMutableURLRequest(URL: NSURL(string: "YOUR URL")!)
var session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
var params = ["username":"username", "password":"password"] as Dictionary<String, String>
request.HTTPBody = try? NSJSONSerialization.dataWithJSONObject(params, options: [])
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
print("Response: \(response)")})
task.resume()
For asynchronously query, from Apple docs
Like most networking APIs, the NSURLSession API is highly
asynchronous. It returns data in one of two ways, depending on the
methods you call:To a completion handler block that returns data to your app when a
transfer finishes successfully or with an error.By calling methods on your custom delegate as the data is received.
By calling methods on your custom delegate when download to a file is
complete.
Swift AsynchronousRequest response cannot be read
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)")
}
}
how to use sendAsynchronousRequest:queue:completionHandler:
PArt 1:
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
if ([data length] > 0 && error == nil)
[delegate receivedData:data];
else if ([data length] == 0 && error == nil)
[delegate emptyReply];
else if (error != nil && error.code == ERROR_CODE_TIMEOUT)
[delegate timedOut];
else if (error != nil)
[delegate downloadError:error];
}];
NSURLConnection sendAsynchronousRequest: How to check finished status code?
You have to implement 2 delegate methods:
Status code:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
Received data:
- (void)connection:(NSURLConnection *)connection
didReceiveData:(NSData *)data
Example usage:
Declaration
@interface RequestHandler : NSObject <NSURLConnectionDelegate>
{
NSMutableData *receivedData;
}
Request
- (void)sendRequest:(NSString *)surveyorId withData:(NSData *)requestData
{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
// Apply params in http body
if (requestData) {
[request setHTTPBody:requestData];
}
[request setURL:url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
}
Delegates
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSHTTPURLResponse *responseCode = (NSHTTPURLResponse *)response;
if ([self.delegate respondsToSelector:@selector(didReceiveResponseCode:)]) {
[self.delegate didReceiveResponseCode:responseCode];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
receivedData = [[NSMutableData alloc] initWithData:data];
if ([self.delegate respondsToSelector:@selector(connectionSucceedWithData:)]) {
[self.delegate connectionSucceedWithData:receivedData];
}
}
Related Topics
Linking Error When Building Parse in Xcode 7
What Does the Underscore in a Function Declaration Do
Rotation Gesture Produces Undesired Rotation
How to Pass Arguments into a Function with Completion Swift
Core Data Update in Swift While Selecting Any Row in List Table View Not Working
String Nil Inside Nsurlsession
Unrecognized Selector Sent to Instance When No Related Entities Found in Core Data
How to Get All Text from a PDF in Swift
Secure Text .Echosbullets Not Working for Password Field
Nsurl from String Gets Truncated, Dots on the Uivideoeditorcontroller's Video Path Swift 2 iOS 8
How to Resume a Published Timer in Swiftui After Navigating to a Different Page
Elegant 'Bounded' Methodology in Swift