retry request when the internet connection is back - IOS - ios

I am using AFNetworking 3.0 to perform Web request in my application.
Is there a way to automatically retry a request when the internet is back?
This is the request code:
#try {
NSString *urlMuniByGov = [NSString stringWithFormat:#"%#/%#", URL_MUNICIPALITES, selectedGov.govID];
NSURL *url = [NSURL URLWithString:urlMuniByGov];
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] init];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
manager.securityPolicy.allowInvalidCertificates = YES;
[manager GET:url.absoluteString
parameters:nil
progress:nil
success:^(NSURLSessionDataTask * task, id responseObject) {
NSArray *muniNSArray = [responseObject objectForKey:#"municipalites"];
if ([muniNSArray isKindOfClass:[NSArray class]]){
for (NSDictionary *dictionary in muniNSArray) {
Municipality *munModel = [Municipality new] ;
munModel.munID = [dictionary objectForKey:#"id"];
munModel.munNameAr = [[dictionary objectForKey:#"nom"] objectForKey:#"ar"];
munModel.munNameFr = [[dictionary objectForKey:#"nom"] objectForKey:#"fr"];
[self.munsArray addObject:munModel];
[self.munsString addObject:munModel.munNameAr];
}
}
[municipalityText setItemList:[NSArray arrayWithArray:self.munsString]];
} failure:^(NSURLSessionDataTask * task, NSError * error) {
NSLog(#"Error: %#", error);
}];
}
#catch (NSException *exception) {
NSLog(#"Exception: %#", exception);
}

[[AFNetworkReachabilityManager sharedManager]setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
NSLog(#"Reachability: %#", AFStringFromNetworkReachabilityStatus(status));}];
if any changes in the net connection this block will call , so here u can retry a request
for additional information follow the link https://github.com/AFNetworking/AFNetworking#network-reachability-manager

Related

Refresh access token automatically using AFOAuth2Manager

I have a server with OAuth 2.0 implemented for issuing access and refresh tokens. The client for this server is an iOS App written in Objective-C. I am currently using AFNetworking 3.0 for HTTP requests and AFOAuth2Manager to handle authorization. I want to refresh my access token stored in iOS app using the refresh token issued by the server before the access token expires (server returns number of seconds to expire as { 'expires_in': 3600 } (one hour)). Everything is working fine until the access token expires. Below is my code for handling requests and authorization.
- (AFJSONRequestSerializer *)setRequestSerializer
{
AFJSONRequestSerializer *serializer = [AFJSONRequestSerializer serializer];
[serializer setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[serializer setValue:#"application/json" forHTTPHeaderField:#"Accept"];
User *currentUser = [User currentUser];
if (currentUser){
AFOAuthCredential *credentials = [AFOAuthCredential retrieveCredentialWithIdentifier:kEndpointServer];
if (!credentials.isExpired){
[serializer setAuthorizationHeaderFieldWithCredential:credentials];
}
}
return serializer;
}
- (AFJSONResponseSerializer *)setResponseSerializer
{
AFJSONResponseSerializer *serializer = [AFJSONResponseSerializer serializer];
return serializer;
}
- (AFSecurityPolicy *)setSecurityPolicy
{
NSString *certFilePath = [[NSBundle mainBundle] pathForResource:#"cert" ofType:#"cer"];
NSData *certData = [NSData dataWithContentsOfFile:certFilePath];
NSSet *pinnedCerts = [NSSet setWithObject:certData];
AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:pinnedCerts];
[policy setAllowInvalidCertificates:YES]; // DEVELOPMENT ONLY
[policy setValidatesDomainName:NO];
return policy;
}
- (AFHTTPSessionManager *)sessionManager
{
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.securityPolicy = [self setSecurityPolicy];
manager.requestSerializer = [self setRequestSerializer];
manager.responseSerializer = [self setResponseSerializer];
return manager;
}
- (AFOAuth2Manager *)OAuth2Manager
{
NSURL *baseURL = [NSURL URLWithString:kEndpointServer];
AFOAuth2Manager *manager = [[AFOAuth2Manager alloc] initWithBaseURL:baseURL clientID:kParamAPIClientId secret:kParamAPIClientSecret];
manager.securityPolicy = [self setSecurityPolicy];
return manager;
}
- (void)loginUser:(NSDictionary *)user block:(void (^)(BOOL, NSError *))result
{
// Set endpoint URL
NSString *loginEndpointURL = [NSString stringWithFormat:#"%#%#", kEndpointServer, kEndpointLogin];
AFHTTPSessionManager *manager = [self sessionManager];
if ([self internetConnectionAvailable]){
[manager POST:loginEndpointURL parameters:user progress:nil success:^(NSURLSessionDataTask *task, id responseObject){
NSDictionary *responseDict = (NSDictionary *)responseObject;
BOOL success = (BOOL)[(NSNumber *)[responseDict objectForKey:kParamSuccess] boolValue];
NSString *msg = (NSString *)[responseDict objectForKey:kParamMessage];
if (success){
// Get user
NSDictionary *userLoggedIn = (NSDictionary *)[responseDict objectForKey:kParamUser];
//NSLog(#"Logged in.");
NSString *tokenEndpointURL = [NSString stringWithFormat:#"/api%#%#", kEndpointOAuth, kEndpointToken];
OAuth2Manager *OAuth2Manager = [self OAuth2Manager];
[OAuth2Manager authenticateUsingOAuthWithURLString:tokenEndpointURL username:(NSString *)[user objectForKey:kParamEmail] password:(NSString *)[user objectForKey:kParamPassword] scope:nil success:^(AFOAuthCredential *credentials){
NSLog(#"Credentials:");
NSLog(#"Access Token: %#", credentials.accessToken);
NSLog(#"Refresh Token: %#", credentials.refreshToken);
// Store credentials
[AFOAuthCredential storeCredential:credentials withIdentifier:kEndpointServer];
// Set current user
[User setCurrentUser:userLoggedIn];
result(YES, nil);
}failure:^(NSError *error){
NSLog(#"Error authenticating user: %#", error);
result(NO, error);
}];
} else {
result(NO, [NSError errorWithDomain:msg code:kEDHTTPRequestFailedErrorCode userInfo:nil]);
}
}failure:^(NSURLSessionDataTask *task, NSError *error){
result(NO, error);
}];
} else {
result(NO, [NSError errorWithDomain:kEDNoInternetConnectionErrorDomain code:kEDNoInternetConnectionErrorCode userInfo:nil]);
}
}
I have found a similar question on SO:
How to automatically refresh expired token with AFOAuth2Manager?
But the problem with the answer given is that it is outdated (Works with AFNetworking 2.X.X, but does not work with AFNetworking 3.0).
What is the best practice for handling the refreshing of the access token automatically?

SVProgressHUD dismiss not working in custom class

Firstly, I've added some functions which need to call from different ViewControllers in one class file. For those function, I've add SVProgressHUD as preprocess and dismiss after all process is finished. SVProgressHUD is displaying correctly before process is started. But after process, SVProgressHUD is never dismissed at all. Please let me know how to solve that issue.
I've added [SVProgressHUD dismiss]; in all process is finished. But never dismissed.
common.m
- (NSDictionary *) loadBlahClass:(NSString *)paramUserId {
[SVProgressHUD showWithStatus:#"Loading Cards..."];
__block NSDictionary *jsonResponse;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
manager.requestSerializer = [AFJSONRequestSerializer serializer];
[manager.responseSerializer.acceptableContentTypes setByAddingObject:#"application/json"];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
NSString *urlStr = [NSString stringWithFormat:#"MY_URL"];
[manager GET:urlStr parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSString *jsonString = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
[SVProgressHUD dismiss];
dispatch_semaphore_signal(semaphore);
}
failure:
^(AFHTTPRequestOperation *operation, NSError *error) {
[SVProgressHUD dismiss];
[self showAlert:APP_NAME alertMessage:[error localizedDescription]];
dispatch_semaphore_signal(semaphore);
}];
[SVProgressHUD dismiss];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
return jsonResponse;
}
testViewController.m
_allTableData = [[NSMutableArray alloc]init];
NSDictionary *jsonResponse = [commClass loadBlahClass:strUserId];
NSNumber *status = [jsonResponse valueForKey:#"Success"];
NSString *message = [jsonResponse valueForKey:#"Message"];
NSArray *dataArray = [jsonResponse valueForKey:#"lstCC"];
if([status intValue] == 1) {
for(int i=0; i<[dataArray count]; i++) {
//working .......
}
[_ccTable reloadData];
[SVProgressHUD dismiss];
} else {
[commClass showAlert:APP_NAME alertMessage:message];
[SVProgressHUD dismiss];
}
I've found answer. Something like that.
[SVProgressHUD show];
__block BOOL result;
dispatch_async(queue, ^{
result = [self autanticate];
NSLog(#"autantication result = %d", result);
result = [self getCSRFToken];
NSLog(#"Login success result = %d", result);
dispatch_async(dispatch_get_main_queue(), ^{
[SVProgressHUD dismiss];
})
});

How to return an NSArray in the success block, iOS, Objective-C

this is my code. I want to return an array with data after data assign from the web service to the array.I have use block to check.
this is from my header file...
typedef void(^FailureBlock)(NSError *error);
typedef void(^SuccessBlock) (NSMutableArray *responseArray);
this is my implementation file ....
- (void)setupConnectionWithsuccess:(SuccessBlock)success failure:(FailureBlock)failure
{
airportArray = nil;
NSString *airportCode = [NSString stringWithFormat:#"some code"];
NSString *authenticationCode = [NSString stringWithFormat:#"some api"];
NSString *baseurl = [NSString stringWithFormat:#"some url",authenticationCode,airportCode];
// NSString *mainurlString = [NSString stringWithFormat:#""];
// NSURL *mainurl = [NSURL URLWithString:mainurlString];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager GET:baseurl parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSArray *mainArray = (NSArray *)responseObject;
airportArray = [[NSMutableArray alloc] init];
for (NSDictionary *all in mainArray) {
airports = [all objectForKey:#"Airport"];
[airportArray addObject:airports];
NSLog(#"%#", airports);
}
if(success){
success(airportArray);
}
//NSLog(#"%#", responseObject);
}
failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if (failure) {
failure(error);
}
UIAlertController *mainAlert = [UIAlertController alertControllerWithTitle:#"Something Wrong!" message:[error localizedDescription] preferredStyle:UIAlertControllerStyleAlert];
[self presentViewController:mainAlert animated:YES completion:nil];
}];
}
then after success, I want to return the array from this method.how can I do that
- (NSArray *)returnAll
{
[self setupConnectionWithsuccess:^(NSMutableArray *responseArray) {
} failure:^(NSError *error) {
}];
}
please help me with this.I'm new to iOS Block.
Try as follow here i use id because in id you can pass anyobject
- (void)setupConnectionWithsuccess:(void (^)(id responseObject, NSError *error))completion{
airportArray = nil;
NSString *airportCode = [NSString stringWithFormat:#"some code"];
NSString *authenticationCode = [NSString stringWithFormat:#"some api"];
NSString *baseurl = [NSString stringWithFormat:#"some url",authenticationCode,airportCode];
// NSString *mainurlString = [NSString stringWithFormat:#""];
// NSURL *mainurl = [NSURL URLWithString:mainurlString];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager GET:baseurl parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSArray *mainArray = (NSArray *)responseObject;
airportArray = [[NSMutableArray alloc] init];
for (NSDictionary *all in mainArray) {
airports = [all objectForKey:#"Airport"];
[airportArray addObject:airports];
NSLog(#"%#", airports);
}
if (completion)
completion(responseObject,nil);
//NSLog(#"%#", responseObject);
}
failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if (completion)
completion(nil,error);
UIAlertController *mainAlert = [UIAlertController alertControllerWithTitle:#"Something Wrong!" message:[error localizedDescription] preferredStyle:UIAlertControllerStyleAlert];
[self presentViewController:mainAlert animated:YES completion:nil];
}];}
and to call it
[self setupConnectionWithsuccess:^(id responseObject, NSError *error) {
if (responseObject) {
NSLog(#"responsceObect");
}
}];
It get nothing while your function return. Because your block excute at asynchonize way. you should modify your function to handle the Array data in a block.

POST with URL parameters and JSON body in AFNetworking

I'd like to make a POST call that has both URL parameters and a JSON body:
URL http://example.com/register?apikey=mykey
JSON { "field" : "value"}
How can I use two different serializers at the same time with AFNNetworking? Here's my code with the URL parameters missing:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
[manager POST:#"http://example.com/register" parameters:json success:^(AFHTTPRequestOperation *operation, id responseObject) {
I make a post method
/**
* Services gateway
* Method get response from server
* #parameter -> object: request josn object ,apiName: api endpoint
* #returm -> void
* #compilationHandler -> success: status of api, response: respose from server, error: error handling
*/
+ (void)getDataWithObject:(NSDictionary *)object onAPI:(NSString *)apiName withController:(UIViewController*)controller
:(void(^)(BOOL success,id response,NSError *error))compilationHandler {
controller = controller;
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
// set request type to json
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
// post request to server
[manager POST:apiName parameters:object success:^(AFHTTPRequestOperation *operation, id responseObject) {
// NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:responseObject
options:0
error:&error];
//NSString *JSONString = [[NSString alloc] initWithBytes:[jsonData bytes] length:[jsonData length] encoding:NSUTF8StringEncoding];
////
// check the status of API
NSDictionary *dict = responseObject;
NSString *statusOfApi = [[NSString alloc]initWithFormat:#"%#"
,[dict objectForKey:#"OK"]];
// IF Status is OK -> 1 so complete the handler
if ([statusOfApi isEqualToString:#"1"] ) {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
compilationHandler(TRUE,responseObject,nil);
} else {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
NSArray *errorMessages = [responseObject objectForKey:#"messages"];
NSString *message = [errorMessages objectAtIndex:0];
[Utilities showAlertViewWithTitle:apiName message:message];
compilationHandler(FALSE,responseObject,nil);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSString *message = [NSString stringWithFormat:#"%#",[error localizedDescription]];
NSLog(#"Message is %#", message);
NSString *errorMessage = [NSString stringWithFormat:#"%#",[error localizedDescription]];
if (!([message rangeOfString:#"The request timed out."].location == NSNotFound)) {
[Utilities showAlertViewWithTitle:apiName message:errorMessage];
}
compilationHandler(FALSE,errorMessage,nil);
}];
// For internet reachibility check if changes its state
[self checkInternetReachibility:manager];
}
**for Example when we call the Service **
// calling service gateway API
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
"field",#"value",
nil];
[self getDataWithObject:dict onAPI:KGet_Preferences withController:(UIViewController*)controller :^(BOOL success, id response, NSError *error) {
if( success ) {
NSMutableDictionary *data = [[response valueForKey:#"data"] valueForKey:#"preferences"];
compilationHandler(success,data,error);
} else {
compilationHandler(success,nil,error);
}
}];
I believe there is no automatic way of doing it. However, there is a simple way of achieving it manually:
- (NSMutableURLRequest *)someRequestWithBaseURL:(NSString *)baseUrl
method:(NSString *)method
path:(NSString *)path
uriParameters:(NSDictionary *)uriParameters
bodyParameters:(NSDictionary *)bodyParameters
NSURL *url = [NSURL URLWithString:path relativeToURL:[NSURL URLWithString:baseUrl]];
AFHTTPRequestSerializer *httpRequestSerializer = [AFJSONRequestSerializer serializerWithWritingOptions:0]
NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithDictionary:bodyParameters];
if ([httpRequestSerializer.HTTPMethodsEncodingParametersInURI containsObject:method]) {
[parameters addEntriesFromDictionary:uriParameters];
} else {
NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:YES];
// For urlEncodedString, check http://stackoverflow.com/a/718480/856549
urlComponents.percentEncodedQuery = [uriParameters urlEncodedString];
url = [urlComponents URL];
}
NSError *error;
NSURLRequest *request = [httpRequestSerializer requestWithMethod:method
URLString:[url absoluteString]
parameters:parameters
error:&error];

handling the Response with the AFNetworking 2

i am really new to IOS development. i want to develop an application which is dealing with some web services and display in a table view. somehow i found a 3rd party library for do the networking stuffs [AFNetworking 2]. below is my code to get the json response for any given url and parameters.
-(NSDictionary*)getWebServiceResponce:(NSString *)url :(NSDictionary *)object
{
// NSDictionary *parameters = [[NSDictionary alloc] initWithObjectsAndKeys:#"47", #"caregiverPersonId", nil];
__block NSDictionary* result=Nil;
__block NSString* person=Nil;
AFSecurityPolicy *policy = [[AFSecurityPolicy alloc] init];
[policy setAllowInvalidCertificates:YES];
AFHTTPRequestOperationManager *operationManager = [AFHTTPRequestOperationManager manager];
[operationManager setSecurityPolicy:policy];
operationManager.requestSerializer = [AFJSONRequestSerializer serializer];
operationManager.responseSerializer = [AFJSONResponseSerializer serializer];
[operationManager POST:url
parameters:object
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", [responseObject description]);
person = [responseObject[#"d"]objectForKey:#"PersonId"];
// [self returnedResponce:responseObject];
result = (NSDictionary *) responseObject[#"d"];
NSLog(#"RESULT: %#", result);
NSLog(#"personm: %#", person);
[operation waitUntilFinished];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", [error description]);
//result = [error];
}
];
return result;
}
this code works perfectly.. but my point is when i put some breakpoints to check what are the values i got for several variables, it shows null. but my log shows the entire json response.
and i want to return my response object as a dictionary. because i want to do some process with the response.. can some one help me with this ?
The problem is that result is nil when it gets returned. AFNetworking uses ObjC's awesome blocks, they get executed asynchronously. Read more about it here.
You should include a callback block in your getWebServiceResponce method. I've thrown together a bit of code but you should really read more about blocks.
-(void)webServiceResponceForURL:(NSString *)url dictionary:(NSDictionary *)object success:(void (^)(NSDictionary *responseObject))success {
// NSDictionary *parameters = [[NSDictionary alloc] initWithObjectsAndKeys:#"47", #"caregiverPersonId", nil];
__block NSDictionary* result=Nil;
__block NSString* person=Nil;
AFSecurityPolicy *policy = [[AFSecurityPolicy alloc] init];
[policy setAllowInvalidCertificates:YES];
AFHTTPRequestOperationManager *operationManager = [AFHTTPRequestOperationManager manager];
[operationManager setSecurityPolicy:policy];
operationManager.requestSerializer = [AFJSONRequestSerializer serializer];
operationManager.responseSerializer = [AFJSONResponseSerializer serializer];
[operationManager POST:url
parameters:object
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", [responseObject description]);
person = [responseObject[#"d"]objectForKey:#"PersonId"];
// [self returnedResponce:responseObject];
result = (NSDictionary *) responseObject[#"d"];
NSLog(#"RESULT: %#", result);
NSLog(#"personm: %#", person);
//We are executing the block as soon as we have the results.
if (success) {
success(responseObject);
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", [error description]);
//result = [error];
}
];
}
Edit:
[self webServiceResponceForURL:#"foo://foo" dictionary:nil success:^(NSDictionary *responseObject) {
//your code here
}
[self webServiceResponceForURL:#"foo://foo" dictionary:nil success:^(NSDictionary *responseObject) {
//your code here
}
Here you will got complete responseObject in form NSDictionary. You can assign responseObject to instance variable. Now This instance Variable will be used at point time. in your case, it will passed on button event.

Resources