Fixing Nsurlconnection Deprecation from Swift 1.2 to 2.0

Fixing NSURLConnection Deprecation from Swift 1.2 to 2.0

(Repeating my arguments from https://stackoverflow.com/a/30670518/1187415:)

Checking if a resource exists on a server requires sending a HTTP
request and receiving the response. TCP communication can take some
amount of time, e.g. if the server is busy, some router between the
client and the server does not work correctly, the network is down
etc.

That's why asynchronous requests are always preferred. Even if you
think that the request should take only milliseconds, it might
sometimes be seconds due to some network problems. And – as we all
know – blocking the main thread for some seconds is a big no-no.

That being said, you can use a "counting semaphore" or a "dispatch group" to wait for the completion of some asynchronous task.
You should not use this on the main thread. Blocking the main thread
for up to 3 seconds is not acceptable!

func isHostConnected(hostAddress : String) -> Bool
{
let request = NSMutableURLRequest(URL: NSURL(string: hostAddress.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!)!)
request.timeoutInterval = 3
request.HTTPMethod = "HEAD"

let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
var responseCode = -1

let group = dispatch_group_create()
dispatch_group_enter(group)

session.dataTaskWithRequest(request, completionHandler: {(_, response, _) in
if let httpResponse = response as? NSHTTPURLResponse {
responseCode = httpResponse.statusCode
}
dispatch_group_leave(group)
})!.resume()

dispatch_group_wait(group, DISPATCH_TIME_FOREVER)
return (responseCode == 200)
}

Remarks:

  • Setting the HTTP method to "HEAD" is a small optimization, as the
    server sends only the response header without the actual data.
  • In the case of a illegal host name, response would be nil, and
    responseCode = (response as? NSHTTPURLResponse)!.statusCode would crash.

sendSynchronousRequest is deprecated in ios 9

This is a working example,
You should use NSURLSession, with Request.

     func testPost(sender: UIButton) {
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: NSURL(string: "http://localhost:8080/iOSServer/ios/helloworld/swiftCalculator")!)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.HTTPMethod = "POST"
let d = "4"
let data = "x=4&y=\(d)"
request.HTTPBody = data.dataUsingEncoding(NSASCIIStringEncoding)
let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
if let error = error {
print(error)
}
if let data = data{
print("data =\(data)")
}
if let response = response {
print("url = \(response.URL!)")
print("response = \(response)")
let httpResponse = response as! NSHTTPURLResponse
print("response code = \(httpResponse.statusCode)")

//if you response is json do the following
do{
let resultJSON = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions())
let arrayJSON = resultJSON as! NSArray
for value in arrayJSON{
let dicValue = value as! NSDictionary
for (key, value) in dicValue {
print("key = \(key)")
print("value = \(value)")
}
}

}catch _{
print("Received not-well-formatted JSON")
}
}
})
task.resume()
}

Notice it is not necessary to use the request. you can have a data task with URL, but I added the request because in your code, you have set some headers in the request.

Notice using the completionHandler which will be called when your server responses by http response.

sendSynchronousRequest:returningResponse:error: - What shall I use now?


    sendAsynchronousRequest was deprecated in iOS 9.
    ObjC

 NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithURL:[NSURL URLWithString:londonWeatherUrl]
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
// handle response

}] ];

Swift

let session = NSURLSession.sharedSession()
session.dataTaskWithRequest(request) { (data, response, error) -> Void in
}

You have to create a NSMutableURLRequest object and specify your URL and HTTPmethod.

Note: You can also create a delegate class and add a NSURLSessionDataDelegate protocol to receive response instead of adding all your network code in UI classes.
tutorial1 tutorial2

Best practice to replace a synchronous NSURLConnection with NSURLSession

This answer is not supposed to be best practice. It was just practical for me.

Faced with the situation when a bunch of synchronous requests is executed in background and the order of execution matters I've ended up using the following:

SyncRequestSender.h

#import <Foundation/Foundation.h>

@interface SyncRequestSender : NSObject

+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request
returningResponse:(NSURLResponse **)response
error:(NSError **)error;

@end

SyncRequestSender.m

#import "SyncRequestSender.h"

@implementation SyncRequestSender

+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request
returningResponse:(NSURLResponse **)response
error:(NSError **)error
{
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);


NSError __block *err = NULL;
NSData __block *data;
NSURLResponse __block *resp;

[[[NSURLSession sharedSession] dataTaskWithRequest:request
completionHandler:^(NSData* _data, NSURLResponse* _response, NSError* _error) {
resp = _response;
err = _error;
data = _data;
dispatch_group_leave(group);

}] resume];

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

if (response)
{
*response = resp;
}
if (error)
{
*error = err;
}

return data;
}

@end

Simpliest solution to check if File exists on a webserver. (Swift)

Checking if a resource exists on a server requires sending a HTTP
request and receiving the response. TCP communication can take some
amount of time, e.g. if the server is busy, some router between the
client and the server does not work
correctly, the network is down etc.

That's why asynchronous requests are always preferred. Even if you think
that the request should take only milliseconds, it might sometimes be
seconds due to some network problems. And – as we all know – blocking
the main thread for some seconds is a big no-no.

All that being said, here is a possible implementation for a
fileExists() method. You should not use it on the main thread,
you have been warned!

The HTTP request method is set to "HEAD", so that the server sends
only the response header, but no data.

func fileExists(url : NSURL!) -> Bool {

let req = NSMutableURLRequest(URL: url)
req.HTTPMethod = "HEAD"
req.timeoutInterval = 1.0 // Adjust to your needs

var response : NSURLResponse?
NSURLConnection.sendSynchronousRequest(req, returningResponse: &response, error: nil)

return ((response as? NSHTTPURLResponse)?.statusCode ?? -1) == 200
}

iOS9 sendSynchronousRequest deprecated

Use NSURLSession instead like below,

For Objective-C

NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithURL:[NSURL URLWithString:londonWeatherUrl]
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>

var err: NSError?
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(params, options: nil, error: &err)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")

var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
println("Response: \(response)")})

task.resume()

Wait For Asynchronous Operation To Complete in Swift

you have to pass your async function the handler to call later on:

func application(application: UIApplication!, performFetchWithCompletionHandler completionHandler: ((UIBackgroundFetchResult) -> Void)!) {
loadShows(completionHandler)
}

func loadShows(completionHandler: ((UIBackgroundFetchResult) -> Void)!) {
//....
//DO IT
//....

completionHandler(UIBackgroundFetchResult.NewData)
println("Background Fetch Complete")
}

OR (cleaner way IMHO)

add an intermediate completionHandler

func application(application: UIApplication!, performFetchWithCompletionHandler completionHandler: ((UIBackgroundFetchResult) -> Void)!) {
loadShows() {
completionHandler(UIBackgroundFetchResult.NewData)
println("Background Fetch Complete")
}
}

func loadShows(completionHandler: (() -> Void)!) {
//....
//DO IT
//....
completionHandler()
}


Related Topics



Leave a reply



Submit