I am struggling with basic authentication in Swift.
I have a Rest back end service over SSL and with basic authentication. My objective-c client code works well but the corresponding Swift one doesn't work because the authentication fails.
This is the Swift code:
let sUrl = "HTTPS://localhost:8443/Test_1/rest/Service/returnInfo"
let url: URL = URL(string: sUrl)!
let request: URLRequest = URLRequest(url: url);
let session: URLSession = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: OperationQueue())
let task: URLSessionDataTask = session.dataTask(with: request) { (data, response, inError) in {
...
let httpResponse = response as! HTTPURLResponse
if (httpResponse.statusCode != 200) {
let details = [NSLocalizedDescriptionKey: "HTTP Error"]
let error = NSError(domain:"WS", code:httpResponse.statusCode, userInfo:details)
completionHandler(nil, error);
return
}
...
}
task.resume()
The delegate method is quite similar to the corresponding method in Objective-c:
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
guard challenge.previousFailureCount == 0 else {
challenge.sender?.cancel(challenge)
// Inform the user that the user name and password are incorrect
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
let proposedCredential = URLCredential(user: user!, password: password!, persistence: .none)
completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, proposedCredential)
}
The httpResponse.statusCode is always 401.
The delegate method is called only once, instead the corresponding method in Objective-c is called two times.
Where am I wrong?
UPDATE
The corresponding Objective-c code:
NSString *sUrl = [NSString stringWithFormat:#"HTTPS://localhost:8443/Test_1/rest/Service/returnInfo"];
NSURL *url = [NSURL URLWithString:sUrl];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *inError) {
if (inError != nil) {
completionHandler(0, inError);
return;
}
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if (httpResponse.statusCode != 200) {
NSDictionary *details = #{NSLocalizedDescriptionKey:#"HTTP Error"};
NSError *error = [NSError errorWithDomain:#"WS" code:httpResponse.statusCode userInfo:details];
completionHandler(0, error);
return;
}
NSError *jsonError;
NSDictionary *valueAsDictionary = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&jsonError];
if (jsonError != nil) {
completionHandler(0, jsonError);
return;
}
if (![valueAsDictionary[#"ret"] boolValue]) {
NSInteger code = [valueAsDictionary[#"code"] integerValue];
NSDictionary *details = #{NSLocalizedDescriptionKey:(valueAsDictionary[#"message"]!=nil) ? valueAsDictionary[#"message"] : #""};
NSError *error = [NSError errorWithDomain:#"WS" code:code userInfo:details];
completionHandler(0, error);
return;
}
completionHandler(valueAsDictionary[#"value"], nil);
}];
[task resume];
This is the delegate function:
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {
if ([challenge previousFailureCount] == 0) {
NSURLCredential *newCredential = [NSURLCredential credentialWithUser:_user password:_password persistence:NSURLCredentialPersistenceNone];
completionHandler(NSURLSessionAuthChallengeUseCredential, newCredential);
} else {
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
}
}
I eventually managed to make it working in Swift, even if I don't know because it was not working before.
Apparently, user and password have to be explicitly added to the HTTP headers.
let sUrl = "HTTPS://localhost:8443/Test_1/rest/Service/returnInfo"
let url: URL = URL(string: sUrl)!
let request: URLRequest = URLRequest(url: url);
// Changes from here ...
let config = URLSessionConfiguration.default
let userPasswordData = "\(user!):\(password!)".data(using: .utf8)
let base64EncodedCredential = userPasswordData!.base64EncodedString(options: Data.Base64EncodingOptions.init(rawValue: 0))
let authString = "Basic \(base64EncodedCredential)"
config.httpAdditionalHeaders = ["Authorization" : authString]
let session: URLSession = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue())
// ... to here
let task: URLSessionDataTask = session.dataTask(with: request) { (data, response, inError) in {
...
let httpResponse = response as! HTTPURLResponse
if (httpResponse.statusCode != 200) {
let details = [NSLocalizedDescriptionKey: "HTTP Error"]
let error = NSError(domain:"WS", code:httpResponse.statusCode, userInfo:details)
completionHandler(nil, error);
return
}
...
}
task.resume()
This code is worked for me in Swift 3.0.1:
let login = "username"
let password = "password"
let sUrl = NSURL(string: (urlString as NSString) as String)
let request: URLRequest = URLRequest(url: sUrl as! URL);
let config = URLSessionConfiguration.default
let userPasswordData = "\(login):\(password)".data(using: .utf8)
let base64EncodedCredential = userPasswordData!.base64EncodedString(options: Data.Base64EncodingOptions.init(rawValue: 0))
let authString = "Basic \(base64EncodedCredential)"
config.httpAdditionalHeaders = ["Authorization" : authString]
let session: URLSession = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue())
let task = session.dataTask(with: request as URLRequest) { (data, response, error) -> Void in
print("response \(data)")
let httpResponse = response as! HTTPURLResponse
if (httpResponse.statusCode != 200) {
print(error?.localizedDescription as Any)
print("Handle Error")
}
else{
do {
if let jsonResult = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary {
print("Synchronous\(jsonResult)")
}
} catch let error as NSError {
print(error.localizedDescription)
}
}
}
task.resume()
}
According to your question, this is your request (line) instance.
let request: URLRequest = URLRequest(url: url);
You have not set any header parameters for your request instance, here. Please compare request header and body parameters with you objective C client.
Header params may include - content type as well as other useful confidential param like API keys also.
Check your objective C client request and set same params here in your swift code
Related
I used to create a singleton class in Objective-C to execute all the service calls in my code. However, swift uses closures and I am unable to achieve the same results in Swift. Is there any way to do the same thing in Swift 3?
#implementation ServiceManager
+(id)sharedManager {
static ServiceManager *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
-(NSURLSession *)urlSession {
if (_urlSession) {
return _urlSession;
}
NSURLSessionConfiguration *defaultConfigObject =
[NSURLSessionConfiguration defaultSessionConfiguration];
_urlSession = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:nil delegateQueue:[NSOperationQueue mainQueue]];
_urlSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
_urlSession.sessionDescription = #"net.socialInvesting.nsurlsession";
return _urlSession;
}
-(void)ExecuteRequest:(NSURLRequest *)request withCompletion:(void (^)(id result, NSError *error))completionBlock {
NSURLSessionDataTask * dataTask =[[self urlSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if(error == nil) {
id result = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
completionBlock(result,error);
} else {
NSLog(#"Error: %#", error.localizedDescription);
completionBlock(nil, error);
}
}];
[dataTask resume];
}
#end
I call this function as in code snippet below.
[sharedServiceManager ExecuteRequest:urlRequest withCompletion:^(id result, NSError *error) {
if (result) {
LoginModel *model = [[LoginModel alloc]initWithDictionary:result error:NULL];
ResponseManager *manager = [ResponseManager sharedManager];
manager.loginResponse = model;
completionBlock(YES,NULL);
} else {
completionBlock(NO,error);
}
}];
This is how I tried to do similar execution in swift. But unable to return values.
import UIKit
class ServiceManager: UIView {
var session = URLSession.shared
static let sharedSessionManager = ServiceManager()
class func sharedManager() -> ServiceManager {
return sharedSessionManager
}
func executeGetRequest(with urlString: String, inputDictionary:[String : Any], completionHandler: #escaping () -> (Error?, [[String : Any]])) {
let url = URL.init(string: urlString)
let urlRequest = URLRequest(url: url!)
let task = session.dataTask(with: urlRequest) { (data, response, error) in
if error != nil {
print("ERROR: could not execute request")
} else {
do {
let responseDict = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any]
if let results = responseDict!["results"] as? [[String:Any]] {
completionHandler // How to return results and Error from here to the calling function
}
} catch {
print("ERROR: could not retrieve response")
}
}
}
task.resume()
}
}
Any help would be appreciated.
You just have to write completionHandler(arg1, arg2,...) and put the values you want to return inside the parentheses are you would when calling a function. You should change the completion handler to return optional values for both of its arguments, since if you receive an error, it is better to return a nil than an empty dictionary.
do {
let responseDict = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any]
if let results = responseDict!["results"] as? [[String:Any]] {
completionHandler(nil, responseDict)
}
} catch {
completionHandler(error, nil)
}
Thank you for your help.
With some more research on closures, I achieved the result.
Below is the Singleton ServiceManager I created.
class ServiceManager: NSObject {
// Static Instance variable for Singleton
static var sharedSessionManager = ServiceManager()
// Preventing initialisation from any other source.
private init() {
}
// Function to execute GET request and pass data from escaping closure
func executeGetRequest(with urlString: String, completion: #escaping (Data?) -> ()) {
let url = URL.init(string: urlString)
let urlRequest = URLRequest(url: url!)
URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
// Log errors (if any)
if error != nil {
print(error.debugDescription)
} else {
// Passing the data from closure to the calling method
completion(data)
}
}.resume() // Starting the dataTask
}
// Function to perform a task - Calls executeGetRequest(with urlString:) and receives data from the closure.
func downloadMovies(from urlString: String, completion: #escaping ([Movie]) -> ()) {
// Calling executeGetRequest(with:)
executeGetRequest(with: urlString) { (data) in // Data received from closure
do {
// JSON parsing
let responseDict = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any]
if let results = responseDict!["results"] as? [[String:Any]] {
var movies = [Movie]()
for obj in results {
let movie = Movie(movieDict: obj)
movies.append(movie)
}
// Passing parsed JSON data from closure to the calling method.
completion(movies)
}
} catch {
print("ERROR: could not retrieve response")
}
}
}
}
Usage Example below.
ServiceManager.sharedSessionManager.downloadMovies(from: urlBase) { (movies : [Movie]) in // Object received from closure
self.movies = movies
DispatchQueue.main.async {
// Updating UI on main queue
self.movieCollectionView.reloadData()
}
}
I Hope this helps anybody looking for a similar solution.
I need to parse some data from rss and open related links from parsed rss in swift 2,
for example i want to check this link is valid or not:
rtmp://185.23.131.187:1935/live/jomhori1
or this one :
http://185.23.131.25/hls-live/livepkgr/_defint_/liveevent/livestream.m3u8
My code to check the validation of the url :
let urlPath: String = "http://185.23.131.25/hls-live/livepkgr/_defint_/liveevent/livestream.m3u8"
let url: NSURL = NSURL(string: urlPath)!
let request: NSURLRequest = NSURLRequest(URL: url)
let response: AutoreleasingUnsafeMutablePointer<NSURLResponse?>=nil
var valid : Bool!
do {
_ = try NSURLConnection.sendSynchronousRequest(request, returningResponse: response)
} catch {
print("404")
valid = false
}
I've searched the web but all the method I found wasn't helpful for my issue.
The answer by #sschale is nice, but NSURLConnection is deprecated, it's better to use NSURLSession now.
Here's my version of an URL testing class:
class URLTester {
class func verifyURL(urlPath: String, completion: (isOK: Bool)->()) {
if let url = NSURL(string: urlPath) {
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "HEAD"
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { (_, response, error) in
if let httpResponse = response as? NSHTTPURLResponse where error == nil {
completion(isOK: httpResponse.statusCode == 200)
} else {
completion(isOK: false)
}
}
task.resume()
} else {
completion(isOK: false)
}
}
}
And you use it by calling the class method with a trailing closure:
URLTester.verifyURL("http://google.com") { (isOK) in
if isOK {
print("This URL is ok")
} else {
print("This URL is NOT ok")
}
}
Swift 3.0 with URLSession
class URLTester {
class func verifyURL(urlPath: String, completion: #escaping (_ isOK: Bool)->()) {
if let url = URL(string: urlPath) {
var request = URLRequest(url: url)
request.httpMethod = "HEAD"
let task = URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in
if let httpResponse = response as? HTTPURLResponse, error == nil {
completion(httpResponse.statusCode == 200)
} else {
completion(false)
}
})
task.resume()
} else {
completion(false)
}
}
}
This is better than your answer because it only downloads the response headers instead of the whole page (also, it's better because asynchronous).
I found a solution here in Objective C, so I ported the code to Swift (though you'll need to test it):
class testHandler: NSObject, NSURLConnectionDelegate{
func testURL(urlPath: String){
let url: NSURL = NSURL(string: urlPath)!
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "HEAD"
let connection = NSURLConnection(request: request, delegate: self)
}
func connection(connection: NSURLConnection,
didReceiveResponse response: NSURLResponse){
if response is NSHTTPURLResponse{
if (response as! NSHTTPURLResponse).statusCode==200{
//url exists
}
}
}
}
An Obj-C variation for answer provided by #Moritz:
Note: I was preferring a function instead of a class, but the behavior is the same:
+(void)verifyURL:(NSString*)urlPath withCompletion:(void (^_Nonnull)(BOOL isOK))completionBlock
{
NSURL *url = [NSURL URLWithString:urlPath];
if (url) {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = #"HEAD";
//optional: request.timeoutInterval = 3;
NSURLSessionDataTask *dataTask = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
BOOL isOK = NO;
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
int code = (int)((NSHTTPURLResponse*)response).statusCode;
//note: you may want to allow other http codes as well
isOK = !error && (code == 200);
}
completionBlock(isOK);
}];
[dataTask resume];
} else {
completionBlock(NO);
}
}
and here is a call with timestamps:
NSDate *date1 = [NSDate date];
[AppDelegate verifyURL:#"http://bing.com" withCompletion:^(BOOL isOK) {
NSDate *date2 = [NSDate date];
if (isOK) {
NSLog(#"url is ok");
} else {
NSLog(#"url is currently not ok");
}
NSTimeInterval diff = [date2 timeIntervalSinceDate:date1];
NSLog(#"time to return: %.3f", diff);
}];
For easy use I wrote below code and It's working perfectly.
var video_Url = ""
if let url = NSURL(string: Response),
data = NSData(contentsOfURL: url)
{
video_Url = Response
}
else
{
video_Url = ""
}
I have a dataTaskWithUrl:
var headers: NSDictionary = ["X-Mashape-Key": "my-secret-key" , "Accept" : "application/json"]
var stringUrl = "https://restcountries-v1.p.mashape.com/all"
stringUrl = stringUrl.stringByReplacingOccurrencesOfString(" ", withString: "+")
let url = NSURL(string: stringUrl)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url!, completionHandler: { (data, response, error) -> Void in
if let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as? NSDictionary{
println(jsonResult)
}else{
println("error")
}
})
task.resume()
I want to add headers to my task.
In other words, I would like to convert this code to swift:
NSDictionary *headers = #{#"X-Mashape-Key": #"my-secret-key", #"Accept": #"application/json"};
UNIUrlConnection *asyncConnection = [[UNIRest get:^(UNISimpleRequest *request) {
[request setUrl:#"https://restcountries-v1.p.mashape.com/all"];
[request setHeaders:headers];
}] asJsonAsync:^(UNIHTTPJsonResponse *response, NSError *error) {
NSInteger code = response.code;
NSDictionary *responseHeaders = response.headers;
UNIJsonNode *body = response.body;
NSData *rawBody = response.rawBody;
}];
I am new to dataRequests. I do not understand Objective C code but I made a guess when I looked at that code. I need to use headers because I if I just try going to
https://restcountries-v1.p.mashape.com/all directly, I get an error. I had received that Objective C code from this website: https://www.mashape.com/fayder/rest-countries-v1. Any help in the right direction would be very much appreciated.
Thanks
Update for Swift 4+:
let httpUrl = "http://...."
guard let url = URL(string: httpUrl) else {
return
}
var request = URLRequest(url: url)
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("my-secret-key", forHTTPHeaderField: "X-Mashape-Key")
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
}
task.resume()
Old Post:
If you want to use dataTask
var stringUrl = "https://restcountries-v1.p.mashape.com/all"
stringUrl = stringUrl.stringByReplacingOccurrencesOfString(" ", withString: "+")
let url = NSURL(string: stringUrl)
let session = NSURLSession.sharedSession()
var muableRequest = NSMutableURLRequest(URL: url!)
muableRequest.setValue("application/json", forHTTPHeaderField: "Accept")
muableRequest.setValue("my-secret-key", forHTTPHeaderField: "X-Mashape-Key")
let task = session.dataTaskWithRequest(muableRequest, completionHandler: { (data, response, error) -> Void in
if let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil){
println(jsonResult)
}
})
task.resume()
It's the same answer as #Leo's answer but the syntax for Swift changed a little which is why I think it's good to "update the answer a little". So this should work with Swift 3.
func get(_ url: String) {
if let url = URL(string: url) {
var request = URLRequest(url: url)
// Set headers
request.setValue("headerValue", forHTTPHeaderField: "headerField")
request.setValue("anotherHeaderValue", forHTTPHeaderField: "anotherHeaderField")
let completionHandler = {(data: Data?, response: URLResponse?, error: Error?) -> Void in
// Do something
}
URLSession.shared.dataTask(with: request, completionHandler: completionHandler).resume()
} else {
// Something went wrong
}
i am trying to get a file size from url before downloading
here is the obj-c code
NSURL *URL = [NSURL URLWithString:"ExampleURL"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
[request setHTTPMethod:#"HEAD"];
NSHTTPURLResponse *response;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error: nil];
long long size = [response expectedContentLength];
and here is Swift Code
var url:NSURL = NSURL(string: "ExmapleURL")
var request:NSMutableURLRequest = NSMutableURLRequest(URL: url)
request.HTTPMethod = "HEAD"
var response = NSHTTPURLResponse()
NSURLConnection.sendSynchronousRequest(request, returningResponse: &response , error: nil)
but i have error here
NSURLConnection.sendSynchronousRequest(request, returningResponse: &response , error: nil)
'NSHTTPURLResponse' is not identical to 'NSURLResponse?'
did i miss something in swift here ?
The response parameter has the type
AutoreleasingUnsafeMutablePointer<NSURLResponse?>
which means that you can pass the address of an optional NSURLResponse as argument:
var response : NSURLResponse?
NSURLConnection.sendSynchronousRequest(request, returningResponse: &response , error: nil)
You can then conditionally cast the returned response to a NSHTTPURLResponse:
if let httpResponse = response as? NSHTTPURLResponse {
println(httpResponse.expectedContentLength)
}
Note that you should check the return value of sendSynchronousRequest(), which
is nil if no connection could be made.
It is also recommended to call this
method only from a separate thread (or use sendAsynchronousRequest() instead)
because it can take a while to make a connection
– in particular when using a cellular network – and the main thread would be
blocked otherwise.
Swift 4 solution:
func fetchContentLength(for url: URL, completionHandler: #escaping (_ contentLength: Int64?) -> ()) {
var request = URLRequest(url: url)
request.httpMethod = "HEAD"
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
guard error == nil, let response = response as? HTTPURLResponse, let contentLength = response.allHeaderFields["Content-Length"] as? String else {
completionHandler(nil)
return
}
completionHandler(Int64(contentLength))
}
task.resume()
}
// Usage:
let url = URL(string: "https://s3.amazonaws.com/x265.org/video/Tears_400_x265.mp4")!
fetchContentLength(for: url, completionHandler: { contentLength in
print(contentLength ?? 0)
})
I have the following code in my iOS project and I want to convert to use NSURLSession instead of NSURLConnection. I am querying a REST API which uses a token-based HTTP Authentication scheme but I cannot find an example of how to do it.
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
NSString *username = [[NSUserDefaults standardUserDefaults] stringForKey:#"Username"];
NSString *token = //GET THE TOKEN FROM THE KEYCHAIN
NSString *authValue = [NSString stringWithFormat:#"Token %#",token];
[request setValue:authValue forHTTPHeaderField:#"Authorization"];
if ([NSURLConnection canHandleRequest:request]){
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
[NSURLConnection sendAsynchronousRequest:request queue:self.fetchQueue
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (!connectionError) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if (httpResponse.statusCode == 200){
NSDictionary *jsonData = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers|NSJSONReadingAllowFragments error:nil];
//Process the data
}
}
}];
}
You can rewrite it using NSURLSession as follows
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
NSString *token ; //GET THE TOKEN FROM THE KEYCHAIN
NSString *authValue = [NSString stringWithFormat:#"Token %#",token];
//Configure your session with common header fields like authorization etc
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfiguration.HTTPAdditionalHeaders = #{#"Authorization": authValue};
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
NSString *url;
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
if (!error) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if (httpResponse.statusCode == 200){
NSDictionary *jsonData = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers|NSJSONReadingAllowFragments error:nil];
//Process the data
}
}
}];
[task resume];
This is in Swift, but the logic is the same:
let sessionConfig = NSURLSessionConfiguration.defaultSessionConfiguration()
let url = NSURL(string: "some url")
let request = NSMutableURLRequest(URL: url!)
request.setValue("value", forHTTPHeaderField: "header field")
let urlSession = NSURLSession(configuration: sessionConfig, delegate: self, delegateQueue: NSOperationQueue.mainQueue())
let dataTask = urlSession.dataTaskWithRequest(request) { (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in
}
dataTask.resume()
Set the Authorization header on your URLSession configuration, or directly on your request.
Be advised that Apple says you "should not" attempt to modify the Authorization header in your URLSession configuration:
An URLSession object is designed to handle various aspects of the HTTP protocol for you. As a result, you should not modify the following headers:
Authorization
...
It is, however, possible. If you want to do this, ensure that you set the header configuration before you create the URLSession. It's not possible to modify headers on an existing URLSession.
Here is a Swift playground that shows different scenarios:
import Foundation
// 1: Wrong -- mutating existing config for existing URLSession is no-op
var session = URLSession.shared
session.configuration.httpAdditionalHeaders = ["Authorization": "123"]
let url = URL(string: "https://postman-echo.com/get")!
session.dataTask(with: url) { (data, resp, err) in
if let data = data {
let str = String(bytes: data, encoding: .utf8)!
let _ = str
}
}.resume() // no authorization header
// 2: Setting headers on an individual request works fine.
var request = URLRequest(url: url)
request.addValue("456", forHTTPHeaderField: "Authorization")
session.dataTask(with: request) { (data, resp, err) in
if let data = data {
let str = String(bytes: data, encoding: .utf8)!
let _ = str
}
}.resume() // "headers": { "authorization": "456" }
// 3: You can set headers on a new URLSession & configuration
var conf = URLSessionConfiguration.default
conf.httpAdditionalHeaders = [
"Authorization": "789"
]
session = URLSession(configuration: conf)
session.dataTask(with: url) { (data, resp, err) in
if let data = data {
let str = String(bytes: data, encoding: .utf8)!
let _ = str
}
}.resume() // "headers": { "authorization": "789" }