IOS getting response null in http request - ios

I'm sending a request to a server to test a specific situation. The response is a custom 510 http error and the content is the info of the error.
The web service works fine the first time a send the request. The next time I tried to replicate the error the response is nil. But, if I change the request avoiding the error, it works fine and the response is what it is supposed to be.
I'm executing the request with a brand new object each time.
#interface SCBaseConnection()
#property (strong, nonatomic) NSURLSessionDownloadTask *task;
#end
#implementation SCBaseConnection
- (instancetype) initWithUrl:(NSString *)url
path:(NSString *)path
body:(NSString *)body
headers:(NSDictionary *)headers
method:(NSString *)method
requestCode:(NSInteger)requestCode
{
self = [super init];
NSLog(#"%#", headers);
NSURL *uri = [NSURL URLWithString:[NSString stringWithFormat:#"%#%#", url, path]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:uri];
request.HTTPMethod = method;
if (body) {
request.HTTPBody = [body dataUsingEncoding:NSUTF8StringEncoding];
}
if (headers) {
NSArray *keys = [headers allKeys];
for (NSString *key in keys) {
[request setValue:[headers objectForKey:key] forHTTPHeaderField:key];
}
}
NSURLSession *session = [NSURLSession sessionWithConfiguration: [NSURLSessionConfiguration defaultSessionConfiguration]];
self.task = [session downloadTaskWithRequest:request completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
int statusCode = (int)[response getStatusCode];
NSLog(#"%#", #(statusCode));
if (HTTP_UNAUTHORIZED == statusCode) {
[[NSNotificationCenter defaultCenter] postNotificationName:kUnauthorizedHttpRequest object:response];
}
if (error) {
[MCMGeneralUtils logError:error];
NSLog(#"%#", error.userInfo);
NSLog(#"%#", error);
}
NSData *res = [self dataFromFile:location];
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate didConnectionFinished:self
statusCode:statusCode
response:res
requestPath:path
requestCode:requestCode];
});
}];
return self;
}
This is the content of the error.userInfo after the second request.
NSErrorFailingURLKey = "http://192.168.1.201:23111/api/paciente";
NSErrorFailingURLStringKey = "http://192.168.1.201:2311/api/paciente";
NSLocalizedDescription = "The requested URL was not found on this server.";
The first time the request has no errors.
UPDATE
- (IBAction)save:(UIBarButtonItem *)sender
{
MCMPatientNew *patient = [MCMPatientNew new];
patient.name = self.name;
patient.lastname = self.lastname;
patient.fullname = [NSString stringWithFormat:#"%# %#", self.name, self.lastname];
patient.email = self.email;
patient.phones = [self extracPhones];
patient.patientNew = YES;
NSError *error = nil;
if ([patient assertPatient:&error]) {
MCMUser *user = [MCMUser loadUserInManagedContext:self.managedContext];
patient.delegate = self;
[patient storePatientInManagedContext:self.managedContext];
if ([MCMGeneralUtils isInternetRechable]) {
[self presentViewController:self.serverConnectionAlert animated:YES completion:nil];
[patient postPatientWithToken:user.token doctorId:user.userId];
} else {
[self storeInRequestLogWithRequestCode:REQUEST_CODE_PACIENTE_INSERT
appId:patient.appId
ready:YES
inManagedContext:self.managedContext];
[self cancel:nil];
[self postNotificationWithObject:patient];
}
} else {
[self displayErrorMessageWithErrorInfo:error.userInfo];
}
}
UPDATE 2
- (void)postPatientWithToken:(NSString *)accessToken doctorId:(NSNumber *)doctorId
{
NSMutableDictionary *mutable = [NSMutableDictionary dictionaryWithDictionary:[self jsonToPost]];
[mutable setObject:doctorId forKey:#"doctorId"];
NSDictionary *body = #{#"obj" : mutable};
[self connectToServerWithAccessToken:accessToken
body:body
path:PATH_PACIENTE_INSERT
method:HTTP_METHOD_POST
requestCode:REQUEST_CODE_PACIENTE_INSERT
delegate:self];
}
-
- (void)connectToServerWithAccessToken:(NSString *)accessToken
body:(NSDictionary *)body
path:(NSString *)path
method:(NSString *)method
requestCode:(NSInteger)requestCode
delegate:(id<SCBaseConnectionDelegate>)delegate
{
NSString *authenticator = [NSString stringWithFormat:#"Bearer %#", accessToken];
NSDictionary *headers = #{HEADER_CONTENT_TYPE : CONTENT_TYPE_APPLICATION_JSON,
HEADER_AUTHORIZATION : authenticator};
NSString *bodyStr = body ? [SCJson jsonFromDictionary:body] : #"";
SCBaseConnection *connection = [[SCBaseConnection alloc] initWithUrl:API_URL
path:path
body:bodyStr
headers:headers
method:method
requestCode:requestCode];
connection.delegate = delegate;
[connection execute];
}
-
- (BOOL)execute
{
if (self.task) {
[self.task resume];
return YES;
}
return NO;
}

Related

AFnetworking 3 or 4 GET ResponseObject how to have responseString and ResponseData

Hello I would like to know how it's possible to have responseString and responseObject with the new version of AFNetworking.
When I made GET operation I have success response with NSURLSessionDataTask and id responseData.
And I would like to have responseString and responseObject.
Thanks for your help.
there is my code not the full code but it's like that
void(^wsFailure)(NSURLSessionDataTask *, NSError *) = ^(NSURLSessionDataTask *failedOperation, NSError *error) {
NSLog(#"failed %#",failedOperation);
[self failedWithOperation:failedOperation error:error];
};
void (^wsSuccess)(NSURLSessionDataTask *, id) = ^(NSURLSessionDataTask * _Nonnull succeedOperation, id _Nullable responseObject) {
NSLog(#"responseData: %#", responseObject);
NSString *str = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(#"responseData: %#", str);
}}
AFHTTPResponseSerializer *responseSerializer = [self responseSerializerFromResponseType];
AFHTTPRequestSerializer *requestSerializer = [self requestSerializerFromRequestType];
operationManager.requestSerializer = requestSerializer;
operationManager.responseSerializer = responseSerializer;
- (AFHTTPResponseSerializer *)responseSerializerFromResponseType{
if ([self.request.parameters[#"responseType"] isEqualToString:#"xml"]) {
return [AFXMLParserResponseSerializer serializer];
}
else if ([self.request.parameters[#"responseType"] isEqualToString:#"html"]) {
return [AFHTTPResponseSerializer serializer];
}}
Quickly done, I implemented my own ResponseSerializer, which is just a way to encapsulate a AFNetworkingSerializer (~AFHTTPResponseSerializer which is the superclass of the other ones, and respects the AFURLResponseSerialization protocol) which will return a custom serialized object, which will have the 2 properties you want in addition to the NSDictionary/NSArray serialized object: a NSData and a NSString.
.h
#interface CustomResponseSerializer : NSObject <AFURLResponseSerialization>
-(id)initWithResponseSerializer:(id<AFURLResponseSerialization>)serializer;
#end
.m
#interface CustomResponseSerializer()
#property (nonatomic, strong) id<AFURLResponseSerialization> serializer;
#end
#implementation CustomResponseSerializer
-(id)initWithResponseSerializer:(id<AFURLResponseSerialization>)serializer {
self = [super init];
if (self)
{
_serializer = serializer;
}
return self;
}
- (nullable id)responseObjectForResponse:(nullable NSURLResponse *)response data:(nullable NSData *)data error:(NSError * _Nullable __autoreleasing * _Nullable)error {
id serialized = nil;
if ([_serializer respondsToSelector:#selector(responseObjectForResponse:data:error:)]) {
NSError *serializationError = nil;
serialized = [_serializer responseObjectForResponse:response data:data error:&serializationError];
}
//You could put NSError *serializationError = nil; before, and set it into the `CustomSerializedObject` `error` property, I didn't check more about AFNetworking and how they handle a parsing error
return [[CustomSerializedObject alloc] initWithData:data
string:[[NSString alloc] initWithData:data encoding: NSUTF8StringEncoding]
object:serialized];
}
+ (BOOL)supportsSecureCoding {
return YES;
}
- (void)encodeWithCoder:(nonnull NSCoder *)coder {
[coder encodeObject:self.serializer forKey:NSStringFromSelector(#selector(serializer))];
}
- (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder {
self = [self init];
if (!self) {
return nil;
}
self.serializer = [coder decodeObjectForKey:NSStringFromSelector(#selector(serializer))];
return self;
}
- (nonnull id)copyWithZone:(nullable NSZone *)zone {
CustomResponseSerializer *serializer = [[CustomResponseSerializer allocWithZone:zone] init];
serializer.serializer = [self.serializer copyWithZone:zone];
return serializer;
}
#end
And the object:
#interface CustomSerializedObject: NSObject
#property (nonatomic, strong) NSData *rawData;
#property (nonatomic, strong) NSString *string;
#property (nonatomic, strong) id object;
#property (nonatomic, strong) NSError *error; //If needed
-(id)initWithData:(NSData *)data string:(NSString *)string object:(id)object;
#end
#implementation CustomSerializedObject
-(id)initWithData:(NSData *)data string:(NSString *)string object:(id)object {
self = [super init];
if (self)
{
_rawData = data;
_string = string;
_object = object;
}
return self;
}
#end
How to use:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
NSURL *URL = [NSURL URLWithString:#"https://httpbin.org/get"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
CustomResponseSerializer *responseSerializer = [[CustomResponseSerializer alloc] initWithResponseSerializer:[AFJSONResponseSerializer serializer]];
[manager setResponseSerializer: responseSerializer];
NSURLSessionDataTask *task = [manager dataTaskWithRequest:request
uploadProgress:nil
downloadProgress:nil
completionHandler:^(NSURLResponse * _Nonnull response, CustomSerializedObject * _Nullable responseObject, NSError * _Nullable error) {
NSLog(#"Response: %#", response);
NSLog(#"ResponseObject data: %#", responseObject.rawData); //If you want hex string ouptut see https://stackoverflow.com/questions/1305225/best-way-to-serialize-an-nsdata-into-a-hexadeximal-string
NSLog(#"ResponseObject str: %#", responseObject.string);
NSLog(#"ResponseObject object: %#", responseObject.object);
NSLog(#"error: %#", error);
}];
[task resume];

Obtaining an JSON Token using Authentication in Objective-C

Hi fairly new to iOS just trying to connect the app to an API and get my token using Authentication. I have tried a lot of different options and just can't seem to get my head around it. All i'm trying to do is obtain my token. Can anyone see where I'm going wrong? The API documentation is here: https://simplybook.me/en/api/developer-api
NSURL *url = [NSURL URLWithString:#"http://user-api.simplybook.me/login/"];
NSURLSession *session = [NSURLSession sharedSession];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:#"myloginname" forHTTPHeaderField:#"X-Company-Login"];
[request setValue:#"mytokenhere" forHTTPHeaderField:#"X-Token"];
NSURLSessionDataTask *downloadTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (!error) {
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSArray * resultDict =[json objectForKey:#"name"];
NSLog(#"%#", resultDict);
} else {
NSLog(#"%#", error);
}
}];
[downloadTask resume];
Instead of declaring NSURLSession like this:
NSURLSession *session = [NSURLSession sharedSession];
Try this instead:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
NSURL *url = [NSURL URLWithString:#"https://user-api.simplybook.me/login/"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
And also, make sure you've declared the NSURLSessionDelegate protocol in your header file.
I will give you sample code for getting token but this is regarding to the access and refresh token.You can understand it very clearly now.
ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
}
- (IBAction)actionLogin:(id)sender {
[self loginForGettingAccessandRefreshToken];
}
-(void)loginForGettingAccessandRefreshToken
{
#try {
NSString *strUserName = [textUsername.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSString *strPassword = [textPassword.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSString *strParameters = [NSString stringWithFormat:#"client_id=roclient&client_secret=secret&grant_type=password&username=%#&password=%#&scope=dataEventRecords offline_access", strUserName, strPassword];
id param = strParameters;
NSLog(#"The param is - %#",param);
[GlobalShareClass postLoginDataToServer:BASEURL_LOGIN passParameters:param success:^(id res)
{
if([res isKindOfClass:[NSDictionary class]]){
NSDictionary *dictRes = [res copy];
NSString *strErrDesc = [NSString stringWithFormat:#"%#",[dictRes objectForKey:#"error_description"]];
if([[dictRes allKeys] containsObject:#"error_description"]){
dispatch_async(dispatch_get_main_queue(), ^{
//Dispaly UI
});
}
else{
NSString *strAccessToken = [dictRes objectForKey:#"access_token"];
NSString *strRefreshToken = [dictRes objectForKey:#"refresh_token"];
NSString *strTokenType = [dictRes objectForKey:#"token_type"];
NSString *sstrExpiresIn = [dictRes objectForKey:#"expires_in"];
[[NSUserDefaults standardUserDefaults] setObject:globalShare.strRefreshToken forKey:#"refresh_token"];
[[NSUserDefaults standardUserDefaults] setObject:globalShare.strAccessToken forKey:#"access_token"];
[[NSUserDefaults standardUserDefaults] synchronize];
NSDictionary *responseDict = [GlobalShareClass getDataFromToken:globalShare.strAccessToken];
NSString *strFetchedSub = [[NSUserDefaults standardUserDefaults] stringForKey:#"loginIdSub"];
globalShare.loginId = [responseDict objectForKey:#"sub"];
}
}
else{
NSLog(#"The res starts with array");
}
} failure:^(NSError *error) {
// error handling here ...
NSLog(#"%#", [error localizedDescription]);
dispatch_async(dispatch_get_main_queue(), ^{
//Showing Error
});
} passViewController:self];
}
#catch(NSException *exception){
NSLog(#"%#",[exception description]);
}
#finally{
}
}
}
GlobalShareClass.h
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#interface GlobalShareClass : NSObject{
NSMutableArray *arr;
}
#property (strong, nonatomic) NSMutableArray *arr;
+ (GlobalShareClass *)sharedInstance;
+ (void)postLoginDataToServer:(NSString *)url passParameters:(id)parameter success:(void (^)(id res))successPost failure:(void(^)(NSError* error))failurePost passViewController:(UIViewController *)vc;
+ (NSDictionary *)getDataFromToken:(NSString *)strToken;
+ (NSDictionary *)urlBase64Decode:(NSString *)strToParse;
#end
GlobalShareClass.m
#import "GlobalShareClass.h"
#implementation GlobalShareClass
#synthesize arr;
+ (GlobalShareClass *)sharedInstance {
static GlobalShareClass* _shareInstane = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_shareInstane = [[GlobalShareClass alloc] init];
//Incase array of initialization
_shareInstane.arr = [[NSMutableArray alloc] init];
});
return _shareInstane;
}
+ (void)postLoginDataToServer:(NSString *)url passParameters:(id)parameter success:(void (^)(id res))successPost failure:(void(^)(NSError* error))failurePost passViewController:(UIViewController *)vc{
GlobalShareClass *globalShare = [GlobalShareClass sharedInstance];
__block id jsonResp;
NSData *data = [parameter dataUsingEncoding:NSUTF8StringEncoding];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/x-www-form-urlencoded;charset=UTF-8" forHTTPHeaderField:#"content-type"];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSURLSessionUploadTask *dataTask = [session uploadTaskWithRequest: request
fromData:data completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if(data == nil && error){
NSLog(#"uploadTaskWithRequest error: %#", error);
failurePost(error);
}
else{
jsonResp = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSString *strStatusCode = [NSString stringWithFormat:#"%ld",(long)[((NSHTTPURLResponse *)response) statusCode]];
if([strStatusCode isEqualToString:#"400"]){
successPost(jsonResp);
}
NSString *strStatusCodeResponse = [self strGetStatusResponseCode:strStatusCode];
if([strStatusCodeResponse length] > 0){
dispatch_async(dispatch_get_main_queue(), ^{
// Showing error
});
}else{
jsonResp = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
if([jsonResp objectForKey:#"error"] || jsonResp == nil){
dispatch_async(dispatch_get_main_queue(), ^{
[self showAlertController:#"Error" :[jsonResp objectForKey:#"error_description"] passViewController:vc];
});
}
else
successPost(jsonResp);
}
}
}];
[dataTask resume];
}
+ (NSDictionary *)getDataFromToken:(NSString *)strToken {
NSDictionary *data;
NSString *encoded = [strToken componentsSeparatedByString:#"."][1];
data = [GlobalShareClass urlBase64Decode:encoded];
return data;
}
+ (NSDictionary *)urlBase64Decode:(NSString *)strToParse {
#try {
NSDictionary *returnDict;
NSString *output = [strToParse stringByReplacingOccurrencesOfString:#"-" withString:#"+"];
output = [output stringByReplacingOccurrencesOfString:#"_" withString:#"/"];
switch (output.length % 4) {
case 0:
case 1:
break;
case 2:
output = [output stringByAppendingString:#"=="];
break;
case 3:
output = [output stringByAppendingString:#"="];
break;
default:
break;
}
NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:output options:0];
NSString *decodedString = [[NSString alloc] initWithData:decodedData encoding:NSUTF8StringEncoding];
NSLog(#"%#", decodedString);
NSData *data = [decodedString dataUsingEncoding:NSUTF8StringEncoding];
returnDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
return returnDict;
}
#catch (NSException *exception) {
NSLog(#"%#", [exception description]);
}
}
#end

NSURLSession didReceiveChallenge called for each request

I am using this custom class to download data from Server(ASP.NET IIS 7.5) using a certificate. It works just fine except that on every request the didReceiveChallenge method is called every time and credentials has to be applied again and again. The performance suffers greatly.
How can we avoid this?
Thanks.
#import "ServerRequest.h"
#import <UIKit/UIKit.h>
#implementation ServerRequest{
NSMutableData * recievedData;
NSString * operationName;
NSString * operationParameters;
DataOperationType operationType;
NSURL* downloadURL;
NSData * HTTPBodyData;
UIView * waitView;
UIProgressView * progressView;
}
- (instancetype)init{
if(self = [super init]) {
}
return self;
}
- (NSURLSession *)normalSession{
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLProtectionSpace * protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:[Config getBaseURL] port:443 protocol:#"https" realm:nil authenticationMethod:NSURLAuthenticationMethodClientCertificate];
[configuration.URLCredentialStorage setDefaultCredential:[Helper getCredential] forProtectionSpace:protectionSpace];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:[NSOperationQueue mainQueue]];
return session;
}
- (instancetype)initWithRequest:(NSString *)request
{
if(self = [super init]) {
operationType = DataOperationTypeData;
downloadURL = [NSURL URLWithString:request];
NSLog(#"Created download operation for URL: %#", [downloadURL absoluteString]);
}
return self;
}
- (instancetype)initWithRequest:(NSString *)request Dicionary:(NSString *) dataDictionary{
if(self = [super init]) {
operationType = DataOperationTypeHTMLFrom;
downloadURL = [NSURL URLWithString:request];
NSLog(#"Created download operation for URL: %#", [downloadURL absoluteString]);
operationParameters = dataDictionary;
}
return self;
}
- (instancetype)initWithRequest:(NSString *)request data:(NSData *) bodyData{
if(self = [super init]) {
operationType = DataOperationTypeBodyData;
downloadURL = [NSURL URLWithString:request];
NSLog(#"Created download operation for URL: %#", [downloadURL absoluteString]);
HTTPBodyData = bodyData;
}
return self;
}
- (void) performOperationWithCompletion:(ServerRequestCompletion)onCompletion error:(ServerRequestError)onError{
if (self.showProgressView){
[self configureProgressView];
}
if (self.parentView) {
waitView = [Config createWaitView:self.parentView];
}
self.completion = onCompletion;
self.error = onError;
NSMutableURLRequest *request;
request = [NSMutableURLRequest requestWithURL:downloadURL];
[request setHTTPMethod:#"POST"];
[request setValue:#"utf-8" forHTTPHeaderField:#"Accept-Charset"];
if (operationType == DataOperationTypeHTMLFrom) {
NSData *postData = [operationParameters dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPMethod:#"POST"];
[request setValue:#"utf-8" forHTTPHeaderField:#"Accept-Charset"];
[request setValue:[NSString stringWithFormat:#"%ld", (unsigned long)postData.length] forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
}
else if (operationType == DataOperationTypeBodyData) {
[request setHTTPMethod:#"POST"];
[request setValue:[NSString stringWithFormat:#"%ld", (unsigned long)HTTPBodyData.length] forHTTPHeaderField:#"Content-Length"];
[request addValue: #"multipart/form-data; charset=utf-8" forHTTPHeaderField: #"Content-Type"];
[request setHTTPBody:HTTPBodyData];
}
else{
[request setValue:#"application/x-www-form-urlencoded charset=utf-8" forHTTPHeaderField:#"Content-Type"];
}
NSURLSession * defaultSession = [self normalSession];
NSURLSessionTask * dataTask = [defaultSession dataTaskWithRequest:request];
if (!dataTask) {
self.error([EXError errorWithDomain:[[NSBundle mainBundle] bundleIdentifier] code:-1 userInfo:#{NSLocalizedDescriptionKey: #"Could not initialize connection"}]);
}else{
if (self.showProgressView) {
dispatch_async(dispatch_get_main_queue(), ^{
// AppDelegate_Shared * appDelegate = (AppDelegate_Shared *)([UIApplication sharedApplication]).delegate;
// [appDelegate.progressView setHidden:NO];
// [appDelegate.progressView setProgress:0];
});
}
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
[dataTask resume];
}
}
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler{
//NSURLProtectionSpace *protectionSpace = [challenge protectionSpace];
NSURLCredential *credential = [Helper getCredential];
if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodNTLM])
{
if (challenge.previousFailureCount >= 3)
{
// handle the fact that the previous attempt failed
EXError* error = [EXError errorWithDomain:NSURLErrorDomain code:403 userInfo: #{NSLocalizedDescriptionKey: #"Unable to verify account information."}];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
self.error(error);
}else{
NSURLCredentialPersistence persistence = NSURLCredentialPersistenceForSession;
NSString * userName = [Config getUserName];
NSString * password = [Config getPassword];
NSURLCredential *loginCredential = [NSURLCredential credentialWithUser:userName password:password persistence:persistence];
completionHandler(NSURLSessionAuthChallengeUseCredential, loginCredential);
[self removeWaitView];
}
}
else if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
{
completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
//completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
[self removeWaitView];
}
else if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodClientCertificate)
{ NSLog(#"\n______________________________________________________ Authentication Method Client Certificate _________________________________________________");
completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
[self removeWaitView];
}
else{
completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
[self removeWaitView];
}
}
-(void) configureProgressView{
UIViewController * topController = [Helper currentTopViewController];
if (![topController isKindOfClass:[UINavigationController class]]) {
return;
}
UINavigationController * navigationController = (UINavigationController *)topController;
UINavigationBar * navigationBar = [navigationController navigationBar];
progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleBar];
progressView.frame = CGRectMake(navigationBar.frame.origin.x, navigationBar.frame.size.height - 5, navigationBar.frame.size.width, 5);
[navigationBar addSubview:progressView];
}
-(void) removeWaitView{
[waitView removeFromSuperview];
waitView = nil;
}
- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error{
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSDictionary *responseHeaders = ((NSHTTPURLResponse *)response).allHeaderFields;
NSLog(#"headers: %#", responseHeaders.description);
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if (httpResponse.statusCode >= 400) { // Client/Server Error
EXError * error = [EXError errorWithDomain:[[NSBundle mainBundle] bundleIdentifier] code:httpResponse.statusCode userInfo:#{NSLocalizedDescriptionKey: [NSHTTPURLResponse localizedStringForStatusCode:httpResponse.statusCode]}];
self.error(error);
NSLog(#"Failed with Error %ld : %#", (long)httpResponse.statusCode, [NSHTTPURLResponse localizedStringForStatusCode:httpResponse.statusCode]);
completionHandler(NSURLSessionResponseAllow);
[self removeWaitView];
return;
}
}
completionHandler(NSURLSessionResponseAllow);
[self removeWaitView];
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{
if (!recievedData) {
recievedData = [NSMutableData new];
}
[recievedData appendData:data];
if ([dataTask countOfBytesExpectedToReceive] !=NSURLSessionTransferSizeUnknown) {
double progress = (double)[dataTask countOfBytesReceived] / (double) [dataTask countOfBytesExpectedToReceive];
if (self.showProgressView) {
dispatch_async(dispatch_get_main_queue(), ^{
[progressView setProgress:progress animated:YES];
});
}
}
// DLog(#"progress : %lld", [dataTask countOfBytesExpectedToReceive]);
}
//- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
// didSendBodyData:(int64_t)bytesSent
// totalBytesSent:(int64_t)totalBytesSent
// totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{
// // DLog(#"Did Sent %f", (double)totalBytesSent);
//
// if (self.showProgressView) {
//
// dispatch_async(dispatch_get_main_queue(), ^{
//
// AppDelegate_Shared * appDelegate = (AppDelegate_Shared *)([UIApplication sharedApplication]).delegate;
// [appDelegate.progressView setProgress:
// (double)totalBytesSent /
// (double)totalBytesExpectedToSend animated:YES];
//
// });
// }
//}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
if (self.showProgressView) {
dispatch_async(dispatch_get_main_queue(), ^{
[progressView setHidden:YES];
});
}
// NSString *myString = [[NSString alloc] initWithData:recievedData encoding:NSUTF8StringEncoding];
//
// NSLog(#"%#", myString);
if(error == nil)
{
// SBJSON *json = [SBJSON new];
// NSString *responseString = [[NSString alloc] initWithData:recievedData encoding:NSUTF8StringEncoding];
//
// //NSLog(#"Finished (%#) %d bytes. %#", [downloadURL absoluteString], [data length], responseString);
//
// NSDictionary *dataSet = [json objectWithString:responseString];
NSDictionary* dataSet = [NSJSONSerialization
JSONObjectWithData:recievedData
options:kNilOptions
error:&error];
self.completion(dataSet);
}
else{
// if (error.code == -999) {
// return;
// }
// NSString * httpBody = [[NSString alloc] initWithData:task.currentRequest.HTTPBody encoding:NSUTF8StringEncoding];
//
// httpBody = [NSString stringWithFormat:#"%s\n%#", __PRETTY_FUNCTION__, httpBody];
// [Helper MsgBox:httpBody];
EXError * exError = [EXError errorWithDomain:error.domain code:error.code userInfo:#{NSLocalizedDescriptionKey: [NSHTTPURLResponse localizedStringForStatusCode:error.code]}];
self.error(exError);
// DLog(#"Error %#", [error localizedDescription]);
}
}
#end
One of the reasons can be a check of HTTPS the certificate.
Apple Documentation
This instance contains a protectionSpace property whose authenticationMethod property indicates the kind of challenge being issued (such as a request for a username and password, or a client certificate). You use this value to determine whether you can handle the challenge.
Adding this precondition can check the authentication method and call the handler.
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
completionHandler(NSURLSessionAuthChallengeUseCredential, nil);
return;
}
You can find authentication methods constants here

Encode NSDictionary to send across AFNetworking

How can i URLEncode a NSDictionary so i can send it across AFNetworking.
The code is as follows:
NSMutableDictionary *rus = [[NSMutableDictionary alloc] init];
[rus setValue:#"1211" forKey:#"id"];
[rus setValue:#"33" forKey:#"man"];
How can i Encode this NSDictionary so i can send it across AFNetworking ?
Depends how you wish to send your data:
1) #"application/json" in which case you would use [NSJSONSerialization dataWithJSONObject:parameters options:self.writingOptions error:error]
2) #"application/x-www-form-urlencoded" in which case you basically want to create the string: ?id=1211&man=33 from your dictionary rus.
Here's some code, may not be the most efficient by you get the idea:
NSString *temp;
int i=0;
for(NSString *key in options.params.allKeys)
{
NSString *value = [options.params objectForKey:key];
[parameters setObject:value forKey:key];
if(i==0)
{
temp = [NSString stringWithFormat:#"?%#=%#", key,value];
}
else
{
temp = [NSString stringWithFormat:#"%#&%#=%#", temp, key, value];
}
}
Note: may or may not be relevant to you, but my two cents:
I use AFHTTPSessionManager which handles all the details for me including url encoding, so I just pass in the desired dictionary:
NSMutableDictionary *rus = [[NSMutableDictionary alloc] init];
[rus setValue:#"1211" forKey:#"id"];
[rus setValue:#"33" forKey:#"man"];
[self POST:#"/api/place/nearbysearch" parameters:rus success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(#"nearbyPlaces: success");
[self fetchedPlacesData:responseObject block:block];
if(task != nil && task.originalRequest != nil)
{
NSString *url = [task.originalRequest.URL absoluteString];
[self saveNearbySearchEvent:url params:params];
}
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(#"nearbyPlaces: error: %#", error);
block(self, nil, error);
}];
AFHTTPSessionManager encapsulates a lot of functionality included serializing the data: AFURLRequestSerialization either as JSON or HTTP Request. In case you interested on what AFHTTPSessionManager actually does here's some detail:
A) HTTP Request
Here's the code from AFURLRequestSerialization.m:
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
withParameters:(id)parameters
error:(NSError *__autoreleasing *)error
{
NSParameterAssert(request);
NSMutableURLRequest *mutableRequest = [request mutableCopy];
[self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
if (![request valueForHTTPHeaderField:field]) {
[mutableRequest setValue:value forHTTPHeaderField:field];
}
}];
if (parameters) {
NSString *query = nil;
if (self.queryStringSerialization) {
NSError *serializationError;
query = self.queryStringSerialization(request, parameters, &serializationError);
if (serializationError) {
if (error) {
*error = serializationError;
}
return nil;
}
} else {
switch (self.queryStringSerializationStyle) {
case AFHTTPRequestQueryStringDefaultStyle:
query = AFQueryStringFromParametersWithEncoding(parameters, self.stringEncoding);
break;
}
}
if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
mutableRequest.URL = [NSURL URLWithString:[[mutableRequest.URL absoluteString] stringByAppendingFormat:mutableRequest.URL.query ? #"&%#" : #"?%#", query]];
} else {
if (![mutableRequest valueForHTTPHeaderField:#"Content-Type"]) {
[mutableRequest setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
}
[mutableRequest setHTTPBody:[query dataUsingEncoding:self.stringEncoding]];
}
}
return mutableRequest;
}
B) JSON
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
withParameters:(id)parameters
error:(NSError *__autoreleasing *)error
{
NSParameterAssert(request);
if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
return [super requestBySerializingRequest:request withParameters:parameters error:error];
}
NSMutableURLRequest *mutableRequest = [request mutableCopy];
[self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
if (![request valueForHTTPHeaderField:field]) {
[mutableRequest setValue:value forHTTPHeaderField:field];
}
}];
if (parameters) {
if (![mutableRequest valueForHTTPHeaderField:#"Content-Type"]) {
[mutableRequest setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
}
[mutableRequest setHTTPBody:[NSJSONSerialization dataWithJSONObject:parameters options:self.writingOptions error:error]];
}
return mutableRequest;
}
NSMutableDictionary *rus = [[NSMutableDictionary alloc] init];
[rus setValue:#"1211" forKey:#"id"];
[rus setValue:#"33" forKey:#"man"];
If you are exchanging JSON data with your server:
NSError *error = nil;
NSData *aRequestData = [NSJSONSerialization dataWithJSONObject:rus options:NSJSONWritingPrettyPrinted error:&error];
if (!error) {
[urlRequest setHTTPBody:aRequestData];
}
If you are exchanging PLIST data with your server:
[self stringByAppendingQueryParameters:rus appendQuestionMark:NO];
- (NSString *)stringByAppendingQueryParameters:(NSDictionary *)iParameters appendQuestionMark:(BOOL)iAppendQuestionMark {
BOOL aAppendAmpersand = YES;
NSMutableString *aWorking = [NSMutableString stringWithString:self];
if (iAppendQuestionMark) {
NSRange aQueryBeginning = [self rangeOfString:#"?"];
if (aQueryBeginning.location == NSNotFound) {
[aWorking appendString:#"?"];
aAppendAmpersand = NO;
}
} else {
aAppendAmpersand = NO;
}
for (id aKey in iParameters) {
id aValue = [iParameters valueForKey:aKey];
NSString *aKeyStr = [self convertObjectToURLEncodedValue:aKey];
if (aAppendAmpersand) {
[aWorking appendString:#"&"];
} else {
aAppendAmpersand = YES;
}
if ([aValue isKindOfClass:[NSArray class]]) {
NSArray *aSubParamaters = (NSArray *)aValue;
BOOL aFirstTime = YES;
for (id aSubValue in aSubParamaters) {
NSString *aValueString = [self convertObjectToURLEncodedValue:aSubValue];
if (!aFirstTime) {
[aWorking appendString:#"&"];
}
[aWorking appendString:aKeyStr];
[aWorking appendString:#"="];
[aWorking appendString:aValueString];
aFirstTime = NO;
}
} else {
NSString *aValueString = [self convertObjectToURLEncodedValue:aValue];
[aWorking appendString:aKeyStr];
[aWorking appendString:#"="];
[aWorking appendString:aValueString];
}
}
return [NSString stringWithString:aWorking];
}
- (NSString *)convertObjectToURLEncodedValue:(id)iObject {
NSString *anIntermediate = nil;
if ([iObject isKindOfClass:[NSString class]]) {
anIntermediate = iObject;
} else if ([iObject respondsToSelector:#selector(stringValue)]) {
anIntermediate = [iObject stringValue];
} else {
anIntermediate = [iObject description];
}
NSString *anEncodingString = (__bridge_transfer NSString *)(CFURLCreateStringByAddingPercentEscapes(
NULL,
(__bridge CFStringRef)anIntermediate,
NULL,
(CFStringRef)#"!*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8 ));
return anEncodingString;
}

iOS: EXC_BAD_ACCESS Error NSString length and setHTTPBody

When I start the simulator and the application starts and I click on the UI I get EXC_BAD_ACCESS for NSString *strLength = [NSString stringWithFormat:#"%d", [postStr length]]; and for [req setHTTPBody:[_postStr dataUsingEncoding:NSUTF8StringEncoding. I dont know why this happens. If I uninstall the app but keep the simulator open and run it again I get no errors. Any help would be great. Code is below.
#import "LocavoreRetroAPIAdapter.h"
//Class extention declares a method that is private to the class
#interface LocavoreRetroAPIAdapter ()
-(NSMutableURLRequest *)initRequest:(NSURL *)url method:(NSString *)method;
#end
#implementation LocavoreRetroAPIAdapter
//Called when this class is first initialized
-(id) initWithName:(NSString *)postStr webService:(NSString *)webService spinner: (UIActivityIndicatorView *)spinner{
if(self = [super init]){
_postStr = postStr;
_baseURL = #"http://base/api/";
_webService = webService;
_spinner = spinner;
_result = nil;
}
return self;
}
//Request to Locavore API restful web services
-(void) conn:(NSString *)method{
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
__block NSDictionary *resultBlock = nil;
dispatch_sync(concurrentQueue, ^{
/* Download the json here */
//Create webservice address
NSString *webService = [_baseURL stringByAppendingString:_webService];
//Create the url
NSURL *url = [NSURL URLWithString:webService];
//Create error object
NSError *downloadError = nil;
//Create the request
NSMutableURLRequest *req = [self initRequest:url method:method];
if(req != nil){
//Request the json data from the server
NSData *jsonData = [NSURLConnection
sendSynchronousRequest:req
returningResponse:nil
error:&downloadError];
NSError *error = nil;
id jsonObject = nil;
if(jsonData !=nil){
/* Now try to deserialize the JSON object into a dictionary */
jsonObject = [NSJSONSerialization
JSONObjectWithData:jsonData
options:NSJSONReadingAllowFragments
error:&error];
}
//Handel the deserialized object data
if (jsonObject != nil && error == nil){
NSLog(#"Successfully deserialized...");
if ([jsonObject isKindOfClass:[NSDictionary class]]){
resultBlock = (NSDictionary *)jsonObject;
//NSLog(#"Deserialized JSON Dictionary = %#", resultBlock);
}
else if ([jsonObject isKindOfClass:[NSArray class]]){
NSArray *deserializedArray = (NSArray *)jsonObject;
NSLog(#"Deserialized JSON Array = %#", deserializedArray);
} else {
/* Some other object was returned. We don't know how to deal
with this situation, as the deserializer returns only dictionaries
or arrays */
}
}
else if (error != nil){
NSLog(#"An error happened while deserializing the JSON data.");
}else{
NSLog(#"No data could get downloaded from the URL.");
[self conn:method];
}
}
});
dispatch_sync(dispatch_get_main_queue(), ^{
/* Check if the resultBlock is not nil*/
if(resultBlock != nil){
/*Set the value of result. This will notify the observer*/
[self setResult:resultBlock];
[_spinner stopAnimating];
}
});
});
}
//Configure the request for a post/get method
- (NSMutableURLRequest *)initRequest:(NSURL *)url method:(NSString *)method{
//Create the request
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
//Get the string length
NSString *strLength = [NSString stringWithFormat:#"%d", [_postStr length]];
//Specific to requests that use method post/get
//Configure the request
if([method isEqualToString:#"POST"]){
[req addValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content- Type"];
[req addValue:strLength forHTTPHeaderField:#"Content-Length"];
[req setHTTPMethod:#"POST"];
}else if([method isEqualToString:#"GET"]){
[req addValue:#"text/xml; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[req addValue:strLength forHTTPHeaderField:#"Content-Length"];
[req setHTTPMethod:#"GET"];
}else{
return nil;
}
//Set the HTTP Body
[req setHTTPBody:[_postStr dataUsingEncoding:NSUTF8StringEncoding]];
//Return the request
return req;
}
//Called when this object is destroyed
- (void)dealloc {
NSLog(#"DEALLOC LocavoreRetroAPIAdapter");
[super dealloc];
[_baseURL release];
[_result release];
}
#end
Familiarize yourself the with memory management and object lifetime rules. Your code is crashing because you do not retain (or copy) the arguments within your init... method, and they are being deallocated. Change your init... method to:
-(id) initWithName:(NSString *)postStr webService:(NSString *)webService spinner: (UIActivityIndicatorView *)spinner{
if(self = [super init]){
_postStr = [postStr copy];
_baseURL = #"http://base/api/";
_webService = [webService copy];
_spinner = [spinner retain];
}
return self;
}
Be sure to release the three instance variables you are now copying or retaining in your dealloc method. Also call [super dealloc] as the last step in that method but that's not the source of your problem right now.
//Called when this object is destroyed
- (void)dealloc {
NSLog(#"DEALLOC LocavoreRetroAPIAdapter");
[_postStr release];
[_webService release];
[_spinner release];
[_result release];
[super dealloc];
}
Notice I removed the call to [_baseURL release] from your dealloc as you did not retain it so you do not own the object. If you didn't create an object with alloc or new, and didn't call retain or copy on it, then you don't own the object, so you must not release it.

Resources