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 benil
, andresponseCode = (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 afileExists()
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
Swiftui Hierarchical Picker With Dynamic Data Crashes
Aws Cognito Swift Credentials Provider "Logins Is Deprecated: Use Awsidentityprovidermanager"
What Are the Differences Between Throws and Rethrows in Swift
How to Find the Number of Days in Given Month and Year Using Swift
Swift: 'Hashable.Hashvalue' Is Deprecated as a Protocol Requirement;
How to Obtain the Selected Text from the Frontmost Application in MACos
How to Access a Shadowed Top Level Function in Swift
Please Help Me Intepret This Code Swift
What Versions of Swift Are Supported by What Versions of Xcode
Swift: What Does Backslash Dot "\." Mean
Firebase Snapshot.Key Not Returning Actual Key
Select() from Linq in Swift 3.0
Why Use Required Initializers in Swift Classes
Override Func Error in Swift 2
Swift Imagepickercontroller Didfinishpickingmediawithinfo Not Fired
Read-Only Properties of Protocols in Swift
Swift Firebase Must Be a Non-Empty String and Not Contain '.' '#' '$' '[' or ']'