NSURLSession didReceiveChallenge called for each request - ios

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

Related

NSURLSession Implementation performance issue

My application having around 10 to 30 webservices(both get/post).previously i have used Async NSURLconnection. which takes around 5 sec to excute all services. But now i have replaced NSurlsession which get delay in response compare to nsurlconnection ,it is delayed by 4 to 6 times . here i have attached one of the webservice method code for reference . like below i have code for all methods .
Example NSURLsession code
#pragma mark - NSURLSession
- (NSURLSession *)createSession
{
NSLog(#"DSCReturnAPI: %s",__func__);
static NSURLSession *session = nil;
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfig.timeoutIntervalForRequest = WEBSERVICE_TIMEOUT;
session = [NSURLSession sessionWithConfiguration:sessionConfig
delegate:self
delegateQueue:[NSOperationQueue mainQueue]];
return session;
}
#pragma mark - API Callbacks
-(void)getMyData{
#try {
_webServieRequestType = HWDSCReturnGetRequestType;
NSString *countrycode = [BusinessManager sharedInstance].countryCode;//[HWUserDefaults countryCode];
NSString *userid = [BusinessManager sharedInstance].userId;// [HWUserDefaults userId];
NSString *accessToken = [BusinessManager sharedInstance].accessToken;//[HWUserDefaults accessToken];
NSString *deviceId = [HWUserDefaults deviceId];
[HelperCallbacks logText:[NSString stringWithFormat:#"AccessToken %#",accessToken]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:API_DSCRETURN(countrycode,userid)]];
[request setHTTPMethod:#"GET"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:accessToken forHTTPHeaderField:#"Authorization"];
[request setValue:deviceId forHTTPHeaderField:#"deviceId"];
[request setValue:#"ba598025146eff37e26c9150b180a78b" forHTTPHeaderField:#"If-None-Match"];
theSession = [self createSession];
theDataTask = [theSession dataTaskWithRequest:request];
[theDataTask resume];
}
#catch (NSException *exception) {
[ExceptionHandler sendException:exception];
}
}
#pragma mark - NSURLSessionDataDelegate
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data {
NSLog(#"DSCReturnAPI: %s",__func__);
// NSArray *dataArray = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
if (theSession == session) {
if (_receivedData == nil) {
_receivedData = [[NSMutableData alloc] initWithData:data];
} else {
[_receivedData appendData:data];
}
}
else
{
//NSLog(#"");
}
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
NSLog(#"DSCReturnAPI: %s",__func__);
if (theSession == session) {
[BusinessManager sharedInstance].urlResponseRecieved = NO;
NSLog(#"DSCReturnAPI: httpResponse:%#",response);
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
httpStatusCode =(int) [httpResponse statusCode]; // To track response Code:
NSLog(#"DSCReturnAPI : Http code:%d",httpStatusCode);
NSLog(#"DSCReturnAPI : Headers %#",[httpResponse allHeaderFields]);
_receivedData = [[NSMutableData alloc]init]; }
completionHandler(NSURLSessionResponseAllow);
}
#pragma mark - NSURLSessionTaskDelegate
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
NSLog(#"DSCReturnAPI: %s",__func__);
NSLog(#"DSCReturnAPI: didFailWithError :error : %# errorCode: %ld",error.description,(long)error.code);
#try {
if ([self.serviceDelegate conformsToProtocol:#protocol(ServiceMgrProtocol)] && [self.serviceDelegate respondsToSelector:#selector(webServiceDidFailDSCReturnWithError:)]&& error.code != 0) {
[self.serviceDelegate webServiceDidFailDSCReturnWithError:error.localizedDescription];
}
else {
NSLog(#"DSCReturnAPI:SUCCESS");
[self processResponse];
}
}
#catch (NSException *exception) {
[ExceptionHandler sendException:exception];
}
#finally {
if (theSession) {
theSession = nil;
}
_receivedData = nil;
} }
I think no need to go for such methods of NSURLSession . It has its own block which runs on main thread.
NSMutableURLRequest *request =[[NSMutableURLRequest alloc] initWithURL:requestURL];
NSLog(#"fetchAPromotionWithType = %#", requestURL);
[request setHTTPMethod:#"GET"];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error)
{
dispatch_async(dispatch_get_main_queue(), ^{
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
int responseStatusCode = (int)[httpResponse statusCode];
if ( responseStatusCode == OK_RESPONSE_CODE || responseStatusCode == CREATED_RESPONSE_CODE || responseStatusCode == ACCEPTED_RESPONSE_CODE || responseStatusCode == PARTIAL_RESPONSE_CODE)
{
if (data)
{
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
NSLog(#"Data->%#",dict);
if (dict != nil && [dict isKindOfClass:[NSDictionary class]])
{
NSDictionary *dataDict = [dict objectForKey:#"data"];
if (dataDict != nil && [dataDict isKindOfClass:[NSDictionary class]])
{
//Get your success Data
}
}
}
}
else
{
if (responseStatusCode == 0)
{
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:#"No Connection! Please try again.", #"message", nil];
//Get Your Fail Data
}
else if (data)
{
// NSArray *tempArray = #[#"fan", #"vungle"];
//[JLSharedData sharedManager].savedWaterfallInterstitialArray = nil; //testing
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
//Get Your Fail Data
}
}
});
}];
[task resume];
}];

IOS getting response null in http request

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;
}

Why NSURLConnection didReceiveData not be called in background location update

Please help me, I am coding iOS with background location update and send location data to my server.
below is my code:
#import "AppDelegate.h"
#implementation AppDelegate
- (void)applicationDidEnterBackground:(UIApplication *)application
{
NSLog(#"Went to Background");
[locationManager startMonitoringSignificantLocationChanges];
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
UIApplication *app = [UIApplication sharedApplication];
__block UIBackgroundTaskIdentifier locationUpdateTaskID = [app beginBackgroundTaskWithExpirationHandler:^{
dispatch_async(dispatch_get_main_queue(), ^{
if (locationUpdateTaskID != UIBackgroundTaskInvalid) {
[app endBackgroundTask:locationUpdateTaskID];
locationUpdateTaskID = UIBackgroundTaskInvalid;
}
});
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if ([[locations lastObject] horizontalAccuracy] < 100.0f) {
NSUserDefaults *userDefaults=[NSUserDefaults standardUserDefaults];
mytoken=[userDefaults stringForKey:#"mytoken"];
if (mytoken==nil) {
mytoken=#"";
}
mybgtype=[userDefaults stringForKey:#"mybgtype"];
if (mybgtype==nil) {
mybgtype=#"all";
[userDefaults setObject:mybgtype forKey:#"mybgtype"];
[userDefaults synchronize];
}
CLLocation *newLocation = [locations lastObject];
CLLocation *oldLocation;
if (locations.count > 1) {
oldLocation = [locations objectAtIndex:locations.count-2];
} else {
oldLocation = nil;
}
NSString *NowLng=[[NSNumber numberWithFloat:newLocation.coordinate.longitude] stringValue];
NSString *NowLat=[[NSNumber numberWithFloat:newLocation.coordinate.latitude] stringValue];
UILocalNotification *scheduleAlert;
[[UIApplication sharedApplication] cancelAllLocalNotifications];
scheduleAlert=[[UILocalNotification alloc] init];
scheduleAlert.applicationIconBadgeNumber=1;
scheduleAlert.fireDate=[NSDate dateWithTimeIntervalSinceNow:1];
scheduleAlert.timeZone=[NSTimeZone defaultTimeZone];
scheduleAlert.repeatInterval=NSDayCalendarUnit;
scheduleAlert.soundName=UILocalNotificationDefaultSoundName;
scheduleAlert.alertBody=NowLat;
[[UIApplication sharedApplication] scheduleLocalNotification:scheduleAlert];
if ([mybgtype isEqualToString:#"n"]) {
} else {
[self LoadTaskMyBg:newLocation];
}
}
dispatch_async(dispatch_get_main_queue(), ^{
if (locationUpdateTaskID != UIBackgroundTaskInvalid) {
[app endBackgroundTask:locationUpdateTaskID];
locationUpdateTaskID = UIBackgroundTaskInvalid;
}
});
});
}
-(void) LoadTaskMyBg:(CLLocation *)newLocation
{
NSString *mylat = [NSString stringWithFormat:#"%.8f", newLocation.coordinate.latitude];
NSString *mylng = [NSString stringWithFormat:#"%.8f", newLocation.coordinate.longitude];
NSLog(#"task 1");
receivedDataMyBg=[[NSMutableData alloc] initWithLength:0];
NSString * urlString;
urlString = #"https://www.xx.xx/xx.cshtml";
NSURL * url = [NSURL URLWithString:urlString];
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15.0];
[request setHTTPMethod:#"POST"];
NSString *parameterString=[NSString stringWithFormat:#"%#%#%#%#%#%#%#%#", #"pp=a&tt=",#"aa",#"&mylat=",mylat,#"&mylng=",mylng,#"&myalt=",#"0"];
NSData * postData = [parameterString dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPBody:postData];
connMyBg = [[NSURLConnection alloc] initWithRequest:request delegate:self];
NSLog(#"task 1a");
NSLog(#"%#",parameterString);
if (connMyBg==nil) {
NSLog(#"task 1e");
return;
}
}
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace{
return YES;
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{
//NSLog(#"received authen challenge");
NSLog(#"task challenge");
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
if (connection==connMyBg) {
[receivedDataMyBg setLength:0];
NSLog(#"task connect receive");
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
//NSLog(#"got data %#", [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]);
if (connection==connMyBg) {
[receivedDataMyBg appendData:data];
}
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(#"error");
if (connection==connMyBg) {
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if (connection==connMyBg) {
NSLog(#"task 2");
NSString *response;
NSError *error;
response=[[NSString alloc] initWithData:receivedDataMyBg encoding:NSUTF8StringEncoding];
NSData* data = [response dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *JSONDic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error];
if([[JSONDic objectForKey:#"bnum"] isEqualToString:#""])
{
} else {
UILocalNotification *scheduleAlert;
[[UIApplication sharedApplication] cancelAllLocalNotifications];
scheduleAlert=[[UILocalNotification alloc] init];
scheduleAlert.applicationIconBadgeNumber=1;
scheduleAlert.fireDate=[NSDate dateWithTimeIntervalSinceNow:1];
scheduleAlert.timeZone=[NSTimeZone defaultTimeZone];
scheduleAlert.repeatInterval=NSDayCalendarUnit;
scheduleAlert.soundName=UILocalNotificationDefaultSoundName;
scheduleAlert.alertBody=#"TEST:OK";
}
NSLog(#"%#",[JSONDic objectForKey:#"bnum"]);
}
}
#end
I can get log: "task 1a" ! but why I can't receive "task connect receive" ????
What should I do ?
Thanks.
To use a delegate for either NSURLConnection or CLLocationManager you'll need to create them as properties with a strong reference. Otherwise the delegate implementation will not get called. Since you did not provide the part where you declared those that may be the problem.
NSString* pp =[NSString stringWithFormat:#"xxxx.xx/xx.cshtml, newLocation.coordinate.latitude, newLocation.coordinate.longitude,0.0];
NSURL* response =[NSURL URLWithString:pp];
NSString* response_str =[NSString stringWithContentsOfURL:response encoding:NSUTF8StringEncoding error:nil];
NSLog(#"%#, response of report=%#", pp, response_str);
If I rewrite the code in didUpdateLocations as above,
I can get response_str and it is correct!
But question is: How can it pass ssl https without be challenged ??
even if it ready work very well!

How to waiting asynchronous NSURLConnection response

I am trying to fill a UITableView by fetching an URL. To avoid freeze UI I using dispatch_async(dispatch_queue_t queue, ^(void)block) making asynchronous fetching.
In the asynchronous block using NSRunLoop to waiting response.
Here's my fetching code:
- (BOOL)isFinished {
return _finished;
}
- (void)startReceive {
NSURLRequest* request = [NSURLRequest requestWithURL:self.baseURL];
self.connection = [NSURLConnection connectionWithRequest:request delegate:self];
assert(self.connection);
}
- (void)stopReceiveWithStatus:(NSString*)statusCode {
if (self.connection) {
[self.connection cancel];
self.connection = nil;
}
self.finished = YES;
NSLog(#"Stop Receive with status code %#", statusCode);
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
assert(connection == self.connection);
NSHTTPURLResponse* httpResponse = nil;
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
httpResponse = (NSHTTPURLResponse*) response;
if (httpResponse.statusCode != 409) {
// I need 409 to fetch some data
[self stopReceiveWithStatus:[NSString stringWithFormat:#"HTTP error %2d", httpResponse.statusCode]];
}
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
assert(connection == self.connection);
self.sessionID = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
assert(connection == self.connection);
[self stopReceiveWithStatus:#"Connection failed"];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
assert(connection == self.connection);
[self stopReceiveWithStatus:nil];
}
UITableViewController:
// refreshControl handler
- (IBAction)refresh {
[self startRefreshingAnimation];
dispatch_queue_t loaderQ = dispatch_queue_create("loading transmission data", NULL);
dispatch_async(loaderQ, ^{
[self foo];
while(!self.t.finished) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
dispatch_async(dispatch_get_main_queue(), ^{
[self endRefreshingAnimation]; // end
});
});
}
- (void)foo {
NSLog(#"session id: %#", self.t.sessionID);
}
That sessionID will be filled when HTTP request has done. Now the problem is I can not get the sessionID when first call because the first time it not be filled and second time it works good. How can I get it when first call?
I'm new to iOS. If you have a better solution to solve this problem please tell me, thanks.
There is a good framework, don't waste your time.
https://github.com/AFNetworking/AFNetworking/wiki/Getting-Started-with-AFNetworking
Upd.
You can do your request like:
NSURL *url = self.baseURL;
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
height, #"user[height]",
weight, #"user[weight]",
nil];
[httpClient postPath:#"/myobject" parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSString *responseStr = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(#"Request Successful, response '%#'", responseStr);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"[HTTPClient Error]: %#", error.localizedDescription);
}];
You should use an third-party library to handle network connections, such as STHTTPRequest:
STHTTPRequest *r = [STHTTPRequest requestWithURLString:#"http://www.apple.com"];
r.completionBlock = ^(NSDictionary *headers, NSString *body) {
// ...
};
r.errorBlock = ^(NSError *error) {
// ...
};
[r startAsynchronous];

ASIHTTPRequest set Download Destination Path failing

I have a method which looks for a certain pdf, if it doesn't find it locally it uses ASIHTTPRequest to download it asynchronously. However the request always fails when the line:
[request setDownloadDestinationPath:currentDetailItem];
is uncommented, the request starts and the progress increases until 100% then the request failed block is executed.
These are the relevant NSLogs when the request fails:
2012-08-16 12:08:34.398 XXXX[1675:707] Request started with url :http://XXXX.com/gwas/sites/default/files/Responding%20to%20Severe%20Weather%20Events.pdf
filePath :/var/mobile/Applications/322C24CF-9664-403D-9CC5-13C396F39F84/Documents/Responding%20to%20Severe%20Weather%20Events.pdf
2012-08-16 12:08:39.018 XXXX[1675:707] Request failed:HTTP/1.1 200 OK
Here is the code for the method:
- (void)setDetailItem:(NSString *)newDetailItem {
NSArray *downloadPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSArray *components = [newDetailItem componentsSeparatedByString:#"/"];
NSString *filePath = [[downloadPaths objectAtIndex:0] stringByAppendingFormat:#"/%#", [components lastObject]];
currentDetailItem = filePath;
if (![self fileExistsLocally:[components lastObject]]) {
//Download the file
[self displayProgressView];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:newDetailItem]];
[request setDownloadDestinationPath:currentDetailItem];
[request setDownloadProgressDelegate:progressBar];
[request setCompletionBlock:^
{
[self showPdf:currentDetailItem];
[self hideProgressView];
NSLog(#"%f, Request finished :%#", progressBar.progress, request.responseStatusMessage);
}];
[request setFailedBlock:^
{
NSLog(#"Request failed:%#", request.responseStatusMessage);
[self hideProgressView];
[SVProgressHUD showErrorWithStatus:#"Request failed"];
}];
[request startAsynchronous];
NSLog(#"Request started with url :%#\nfilePath :%#", newDetailItem, currentDetailItem);
}
else {
[self showPdf:currentDetailItem];
}
}
If I comment the line [request setDownloadDestinationPath:currentDetailItem]; out, the request is successful. Any ideas? thanks!
For anyone who is interested, I fixed the problem by swapping over to NSURLConnection, here's the code:
- (void)setDetailItem:(NSString *)newDetailItem {
NSArray *downloadPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSArray *components = [newDetailItem componentsSeparatedByString:#"/"];
NSString *filePath = [[downloadPaths objectAtIndex:0] stringByAppendingFormat:#"/%#", [components lastObject]];
currentDetailItem = filePath;
if (![self fileExistsLocally:[components lastObject]]) {
[self displayProgressView];
data_ = [[NSMutableData alloc] init];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:newDetailItem] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self startImmediately:YES];
if (!connection) {
[SVProgressHUD showErrorWithStatus:#"Request failed"];
return;
}
else {
data_ = [[NSMutableData alloc] init];
}
}
else {
[self showPdf:currentDetailItem];
}
}
#pragma mark NSURLConnectionDelegate methods
- (void)connection: (NSURLConnection*) connection didReceiveResponse: (NSHTTPURLResponse*) response
{
if ([response statusCode] == 200) {
currentDownloadSize = [response expectedContentLength];
}
[data_ setLength:0];
}
- (void) connection: (NSURLConnection*) connection didReceiveData: (NSData*) data
{
[data_ appendData:data];
progressBar.progress = ((float) [data_ length] / (float) currentDownloadSize);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//Save file locally
NSURL *url = [NSURL fileURLWithPath:currentDetailItem];
NSError *error = nil;
[data_ writeToURL:url options:0 error:&error];
if (error) {
NSLog(#"Write failed with error:%#", error);
}
else {
NSLog(#"Request successful");
[self showPdf:currentDetailItem];
}
[self hideProgressView];
}
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
[self hideProgressView];
[SVProgressHUD showErrorWithStatus:#"Request failed"];
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}

Resources