I am using AFNetworking and I've read that synchronous responses are discouraged. yet I need to check whether a user already exist in the online database before the person can go to the next stage of the app. Yes, a typical registration process.
My code as it stands it returns NO because is asynchronous. I need to find a way to check for the success call and return YES or NO depending on this callback.
Could anyone point me in the right direction of how to write an app that waits for the success call so that I know that the user has not been set?
-(BOOL)doesTheUserExistAlreadyOnServer:(NSString *)parsedEmail
{
BOOL *methodResponse = NO;
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:#"http://www.myurl.co.uk/"]];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST"
path:#"http://www.myurl.co.uk/igym.php"
parameters:#{#"myvar2":#"piggy"}];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[httpClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
// Print the response body in text
// NSLog(#"Response: %#", [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]);
if ([[[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding] isEqualToString:#"piggy"]) {
__block methodResponse = YES;
NSLog(#"%#",[[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[operation start];
return (BOOL)methodResponse;
}
EDIT:
I solved the problem using the following logic.
The user clicks on the registration button. The main method does all the preliminary non-web checks, then calls the [self doesTheUserExistAlreadyOnServer:_email.text];
that method code is now
-(void)doesTheUserExistAlreadyOnServer:(NSString *)parsedEmail
{
if(![_spinner isAnimating])
{
[_spinner startAnimating];
}
__block RegistrationViewController* me = self;
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:#"http://www.myurl.co.uk/"]];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST"
path:#"http://www.myurl.co.uk/igym.php"
parameters:#{#"myvar2":#"piggy"}];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[httpClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
// Print the response body in text
if ([[[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding] isEqualToString:#"piggy"]) {
NSLog(#"%#",[[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]);
[me registrationPartTwo:YES];
} else
{
[me registrationPartTwo:NO];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[operation start];
}
Then once that block/callback is successful it calls
-(void)registrationPartTwo:(BOOL)doesItExistOnServer
{
[_spinner stopAnimating];
NSString *emailAlreadyInUseMessage = [NSString stringWithFormat:#"This email is already in use"];
if (doesItExistOnServer)
{
self.screenMsg.text = emailAlreadyInUseMessage;
//here more code to send the user the the next step
}
}
basically i solved this using a 2method registration process dependant upon callback, dont know if thats the best or most efficient way. but thats the way i could solve it on my own.
Use a delegate callback to notify when the operation completes. If needed, before starting the operation, put up an UIActivityIndicatorView (the spinner) to prevent the user from interacting with the app.
Related
Handle single download via afnetworking is good my question is that how handle multiple click on different button then it call this method then process break previous.
it is bcoz suppose several button hit at time then it confuse to download. how handle multiple download in selector method,if in array of batch download then it's easy but through which how .
-(void)downloadimagefromserver:(UIButton *)sender
{
int index =(int) sender.tag;
historyclass *class1 = [messages objectAtIndex:index];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:arrayOfStringsfinal[1]]];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"success");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[operation start];
}
I have a question about AFNetworking 2.0
I have to make a GET request like this:
http://myhost.come/entity?language=en&query=$UserId=14 and $EntityCreationDate>'2014-09-01'
How to generate the Dictionary parameters for this request?
In particular I not understand how can I build this: and $EntityCreationDate>'2014-09-01'
Here I found a good tutorial.
Which states a simple GET request can be sent like this:
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:#"http://samwize.com/"]];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"GET"
path:#"http://samwize.com/api/pigs/"
parameters:nil];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[httpClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
// Print the response body in text
NSLog(#"Response: %#", [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[operation start];
I am trying to connect to Magento REST with OAuth authentication on iOS. I already have: consumer_key, consumer_secret, token, token_secret and the url. With Chrome Rest Client I can connect without problems but in iOS using OAUthiOS library I can not. This library has some example to authenticate to Facebook and Twitter but what I need is to connect to my rest services.
What I have tried so far:
NSString *key = #"Authorization";
NSString *value = #"OAuth realm="http://www.myweb.com/",oauth_consumer_key="xxxx",oauth_token="yyyyy",oauth_nonce="zzzz",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1111111",oauth_version="1.0",oauth_signature="wwwwww"";
request = [[OAuthIORequest alloc] init];
[request addHeaderWithKey:key andValue:value];
[request get:PRODUCTS_SERVICE success:^(NSDictionary *output, NSString *body, NSHTTPURLResponse *httpResponse)
{
NSLog(#"body %#", body);
}];
But nothing happend. What should I do? Is there any framework better?
Thanks!
I have resolved this issue using another framework: AFNetworking and AFOAuth1Client instead of OAUthiOS.
AFOAuth1Client * client = [[AFOAuth1Client alloc] initWithBaseURL:[NSURL URLWithString:BASE_URL] key:CONSUMER_KEY secret:CONSUMER_SECRET];
[client setOauthAccessMethod:#"GET"];
[client setSignatureMethod:AFHMACSHA1SignatureMethod];
[client setDefaultHeader:#"Accept" value:#"application/json"];
[client setAccessToken:[[AFOAuth1Token alloc] initWithKey:TOKEN secret:TOKEN_SECRET session:nil expiration:nil renewable:FALSE]];
NSMutableURLRequest * request =[client requestWithMethod:#"GET" path:PRODUCTS_SERVICE parameters:nil];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[client registerHTTPOperationClass:[AFHTTPRequestOperation class]];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Response: %#", [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[operation start];
How can I run multiple requests inside the success block of 1 request and wait for it to finish?
[manager GET:url parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"%# Response: \n%#", url, responseObject);
resultsArray = [[NSMutableArray alloc] init];
for (NSDictionary *json in [responseObject objectForKey:#"items"]) {
[self getDetails:json];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[SVProgressHUD dismiss];
}];
Where in getDetails:(id)json is the method to load the group of requests whose parameters are based on the result of the main request.
For example:
I would like to request from the API a list of students, then on the success block. For each student, I would like to get the related data from another table (another request) and put them on my NSObject.
EDIT Here is my getDetails method
- (AFHTTPRequestOperation *)getDetails:(NSDictionary *)json
{
NSLog(#"Start Op %#",[json objectForKey:#"related_salon"]);
NSString *url = [NSString stringWithFormat:#"%#read/salons/%#",SERVER_API_URL,[json objectForKey:#"related_salon"]];
NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:req];
//op.responseSerializer = [AFJSONResponseSerializer serializer];
[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success %#",[json objectForKey:#"name"]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failed Op %#",error.localizedDescription);
}];
//AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:req];
//op.responseSerializer = [AFJSONResponseSerializer serializer];
[op start];
return op;
}
The AFNetworking GET method returns a ATHTTPRequestOperation (an NSOperation subclass). You could have your getDetails method return that object. You can then create a new operation dependent upon those operations, which you'd run at the end:
NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
// add here whatever you want to perform when all the getDetails calls are done,
// e.g. maybe you want to dismiss your HUD when all the requests are done.
[SVProgressHUD dismiss];
}];
[manager GET:url parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"%# Response: \n%#", url, responseObject);
resultsArray = [[NSMutableArray alloc] init];
for (NSDictionary *json in [responseObject objectForKey:#"items"]) {
NSOperation *operation = [self getDetails:json];
[completionOperation addDependency:operation];
}
[[NSOperationQueue mainQueue] addOperation:completionOperation];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[SVProgressHUD dismiss];
}];
Again, this is presuming that getDetails is doing its own GET call, and that you change getDetails to (a) capture the NSOperation returned by GET and (b) return it.
I want to implement the following: Have a custom class(so i can call/use it from many parts of my app) where with the help of AFNetworking,i request to the server and get the response.
My code inside the class works,but when i call it from other parts of my app,i am getting a null value. I believe it because of my custom class.Anyway here is my code:
UDIDGen.h
#import <Foundation/NSString.h>
#interface NSString (UDIDGen)
+ (NSString *)getUDID;
#end
UDIDGen.m
#import "UDIDGen.h"
#import "AFHTTPClient.h"
#import "AFHTTPRequestOperation.h"
#implementation NSString (UDIDGen)
+ (NSString *)getUDID{
__strong __block NSString *holder;
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:#"http://domain.com/id.php"]];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"GET"
path:#"http://domain.com/id.php"
parameters:nil];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[httpClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
holder=[NSString stringWithFormat:#"%#",[[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]];
NSLog(#"SERVER RESPONSE: %#",holder);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
[operation start];
return holder;
}
#end
And then when i want to call it from other parts of my app i
#import "UDIDGen.h"
and then
NSString *wsa=[NSString getUDID];
NSLog(#"Response %#",wsa);
For some reasong NSLog(#"SERVER RESPONSE: %#",holder); works and i am able to nslog the server response. But NSString *wsa=[NSString getUDID]; gives me null value.
I believe it has to do with the way i am implementing my custom class, i am doing something wrong.
Any help?
EDIT:My working code so other will use it:
UDIDGen.h
#import <Foundation/NSString.h>
#interface UDIDGen:NSObject{
}
- (void)getUDIDWithCompletion:(void (^)(NSString *udid))completion;
#end
UDIDGen.m
#import "UDIDGen.h"
#import "AFHTTPClient.h"
#import "AFHTTPRequestOperation.h"
#implementation UDIDGen
- (void)getUDIDWithCompletion:(void (^)(NSString *udid))completion {
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:#"http://domain.com/id.php"]];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"GET"
path:#"http://domain.com/id.php"
parameters:nil];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[httpClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSString *udid=[[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(#"SERVER RESPONSE: %#",udid);
if (completion)
{
completion(udid);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// TODO: Handle error
}];
[operation start];
}
#end
Use it like this:
UDIDGen *getResponse = [[UDIDGen alloc] init];
[getResponse getUDIDWithCompletion:^(NSString *udid) {
NSLog(#"SERVER RESPONSE: %#",udid);
}];
You're starting the AFHTTPRequestOperation asynchronously. This means it's running in a separate non-blocking thread, and your method might return before the request has finished.
The easiest way would be to just do this, but this will most likely block the GUI while loading:
[operation startSynchronous];
The cleanest way would be to use a completion block or delegate yourself and inform the target class when a response has been received:
+ (void)getUDIDWithCompletion:(void (^)(NSString *udid))completion {
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:#"http://domain.com/id.php"]];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"GET"
path:#"http://domain.com/id.php"
parameters:nil];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[httpClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSString *udid=[[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(#"SERVER RESPONSE: %#",udid);
if (completion)
{
completion(udid);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// TODO: Handle error
}];
[operation start];
}
You would call this method like so:
[YourCustomClass getUDIDWithCompletion:^(NSString *udid) {
// use udid / update GUI
}];