I am making a project that uses the AFNetworking Library. I use it to check for a login and password with the webservice. This gives me a 200-code back if it is ok. If it is 200, I set a boolean to true so that the application can continue. But this boolean is not set at the right time. I always need to press two times on my login button before it works. Here is my code to set the boolean.
- (BOOL)credentialsValidated {
self.progressHUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
self.progressHUD.labelText = #"Loading";
self.progressHUD.mode = MBProgressHUDModeIndeterminate;
self.progressHUD.dimBackground = YES;
[[API sharedInstance] loginCommand:[NSMutableDictionary dictionaryWithObjectsAndKeys:_txtLogin.text,#"email",_txtPass.text,#"pwd", nil] onCompletion:^(NSDictionary *json){
//completion
if(![json objectForKey:#"error"]){
NSLog(#"status %#",[json valueForKeyPath:#"data.status"]);
if([[json valueForKeyPath:#"data.status"]intValue] == 200){
//Create user object
_loginstatus = YES;
[self.progressHUD hide:YES afterDelay:5];
}else{
//show validation
_txtLogin.text = #"";
_txtPass.text = #"";
_loginstatus = NO;
}
}else {
NSLog(#"Cannot connect to the server");
}
}];
if(_loginstatus){
NSLog(#"true");
}else{
NSLog(#"false");
}
[self.progressHUD hide:YES afterDelay:5];
return _loginstatus;
}
And here is my API code.
-(void)loginCommand:(NSMutableDictionary *)params onCompletion:(JSONResponseBlock)completionBlock{
NSLog(#"%#%#",kAPIHost,kAPILogin);
NSMutableURLRequest *apiRequest = [self multipartFormRequestWithMethod:#"POST" path:kAPILogin parameters:params constructingBodyWithBlock:^(id <AFMultipartFormData>formData){
//TODO: attach file if needed
}];
AFJSONRequestOperation *operation = [[AFJSONRequestOperation alloc] initWithRequest:apiRequest];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject){
//success !
NSLog(#"SUCCESSSS!");
completionBlock(responseObject);
}failure:^(AFHTTPRequestOperation *operation, NSError *error){
//Failure
NSLog(#"FAILUREE!");
completionBlock([NSDictionary dictionaryWithObject:[error localizedDescription] forKey:#"error"]);
}];
[operation start];
}
When I put below [operation start] the [operation waitUntilFinish] code, the app crashes.
Can somebody help me with this?
Kind regards
LOG
Here is a print of my log after I 2 two times pressed the login button
2012-12-28 09:36:00.547 Offitel[6532:907] http://virtuele-receptie.******.sanmax.be/nl/webservice/company-user/****/*****/**************
2012-12-28 09:36:00.561 Offitel[6532:907] false
2012-12-28 09:36:01.604 Offitel[6532:907] SUCCESSSS!
2012-12-28 09:36:01.605 Offitel[6532:907] status 200
2012-12-28 09:36:20.742 Offitel[6532:907] aanmelden pressed
2012-12-28 09:36:20.746 Offitel[6532:907] http://virtuele-receptie.******.sanmax.be/nl/webservice/company-user/****/*****/**************
2012-12-28 09:36:20.748 Offitel[6532:907] true
2012-12-28 09:36:22.184 Offitel[6532:907] SUCCESSSS!
2012-12-28 09:36:22.184 Offitel[6532:907] status 200
If you do this
return _loginstatus;
You are not waiting the operation to finish, so you're not returning what your server is sending to your application. What I usually do in this cases is display an UIActivityIndicator when the login action is fired, and do nothing till' the server has responded. Then, I set the proper values to any variables and in this case I would segue to home screen.
Remember that when you're using AFNetworking you are always doing async stuff.
EDIT
Code example:
- (void)loginActionWithPassword:(NSString *)pass
{
// Add progress HUD to show feedback
// I'm using MBProgressHUD library: https://github.com/jdg/MBProgressHUD#readme
self.progressHUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
self.progressHUD.labelText = #"Loading";
self.progressHUD.mode = MBProgressHUDModeIndeterminate;
self.progressHUD.dimBackground = YES;
// Launch the action to the server
[Actions loginWithEmail:[self.textEmail.text lowercaseString] andPassword:pass success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
if ([Actions requestFailed:JSON]) {
LOG(#"ERROR %# / %# / %# \n", pass, request, response, JSON);
if ([JSON[#"MSG"] isEqualToString:#"USER_NOT_REGISTERED"]) {
self.progressHUD.labelText = #"User doesn't exist";
self.textEmail.text = #"";
self.textPassword.text = #"";
} else if ([JSON[#"MSG"] isEqualToString:#"PASSWORD_INCORRECT"]) {
self.progressHUD.labelText = #"Wrong password";
self.textPassword.text = #"";
}
[self.progressHUD hide:YES afterDelay:[Utils hudDuration]];
return;
}
// If everything went OK, go to this function to save user data
// and perform segue to home screen (or dismiss modal login view)
[self onLoginSuccessWithPassword:pass JSON:JSON response:response];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
// If something fails, display an error message
LOG(#"ERROR:(%#): %# / %# / %# / %# \n", pass, request, response, error, JSON);
self.progressHUD.labelText = #"Something went wrong, try again";
[self.progressHUD hide:YES afterDelay:[Utils hudDuration]];
return;
}];
}
Related
I am using Facebook sdk 3.10 to send a request to multiple friend at a time using FBWebDialogs. Following code I'm using and all thing is fine like selecting multiple friends , sending them request. But there is one problem, is this FBWebDialogs uses some limit of friends as I have more that 300 friends but this is showing only 12-15 friends always.
CODE
[FBWebDialogs
presentRequestsDialogModallyWithSession:nil
message:#"Learn how to make your iOS apps social."
title:nil
parameters:nil
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error) {
if (error) {
// Error launching the dialog or sending the request.
NSLog(#"Error sending request.");
} else {
if (result == FBWebDialogResultDialogNotCompleted) {
// User clicked the "x" icon
NSLog(#"User canceled request.");
} else {
// Handle the send request callback
NSDictionary *urlParams = [self parseURLParams:[resultURL query]];
if (![urlParams valueForKey:#"request"]) {
// User clicked the Cancel button
NSLog(#"User canceled request.");
} else {
// User clicked the Send button
NSString *requestID = [urlParams valueForKey:#"request"];
NSLog(#"Request ID: %#", requestID);
}
}
}
}];
Using above I can see only max 12 friends in the dialog? Am I missing something?
Any help would be appreciated.
You should pass the NSDictionary type object to parameters argument.
You can create like this:
NSArray *suggestedFriends = [[NSArray alloc] initWithObjects:#"fb_id1", #"fb_id2", nil];
NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:[suggestedFriends componentsJoinedByString:#","], #"suggestions", nil];
Now
[FBWebDialogs
presentRequestsDialogModallyWithSession:nil
message:#"Learn how to make your iOS apps social."
title:nil
parameters:params
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error) {
if (error) {
// Error launching the dialog or sending the request.
NSLog(#"Error sending request.");
} else {
if (result == FBWebDialogResultDialogNotCompleted) {
// User clicked the "x" icon
NSLog(#"User canceled request.");
} else {
// Handle the send request callback
NSDictionary *urlParams = [self parseURLParams:[resultURL query]];
if (![urlParams valueForKey:#"request"]) {
// User clicked the Cancel button
NSLog(#"User canceled request.");
} else {
// User clicked the Send button
NSString *requestID = [urlParams valueForKey:#"request"];
NSLog(#"Request ID: %#", requestID);
}
}
}
}];
Here it will show all of the friends with the suggested Facebook ids.
I am trying to create an application that retrieves the current user's email id, user id, user name from his google+ account. The part of the code is as follows,
- (IBAction)googleSigninBtnTapped:(id)sender
{
[GPPSignInButton class];
[GPPSignIn sharedInstance].clientID =[NSString stringWithFormat:#"MY APP ID"];
GPPSignIn *signIn = [GPPSignIn sharedInstance];
signIn.delegate = self;
signIn.shouldFetchGoogleUserEmail = YES;
signIn.shouldFetchGoogleUserID = YES;
signIn.actions = [NSArray arrayWithObjects:
#"http://schemas.google.com/AddActivity",
#"http://schemas.google.com/BuyActivity",
#"http://schemas.google.com/CheckInActivity",
#"http://schemas.google.com/CommentActivity",
#"http://schemas.google.com/CreateActivity",
#"http://schemas.google.com/ListenActivity",
#"http://schemas.google.com/ReserveActivity",
#"http://schemas.google.com/ReviewActivity",
nil];
[signIn trySilentAuthentication];
}
(void)finishedWithAuth:(GTMOAuth2Authentication *)auth error:(NSError )error
{
if (error)
{
NSLog(#"Status: Authentication error: %#", error);
}
else
{
NSLog(#"Status: Authenticated");
NSLog(#"Email: %#",[GPPSignIn sharedInstance].authentication.userEmail);
GTLServicePlus plusService = [[[GTLServicePlus alloc] init] autorelease];
plusService.retryEnabled = YES;
[plusService setAuthorizer:[GPPSignIn sharedInstance].authentication];
GTLQueryPlus *query = [GTLQueryPlus queryForPeopleGetWithUserId:#"me"];
[plusService executeQuery:query completionHandler:^(GTLServiceTicket *ticket, GTLPlusPerson *person, NSError *error)
{
if (error)
{
GTMLoggerError(#"Error: %#", error);
}
else
{
[person retain];
NSLog(#"%#", person.displayName);
NSLog(#"%#", person.identifier);
}
}];
}
}
But when i am trying to execute my app, it gets crashed, saying that
'-[__NSCFString gtm_stringByUnescapingFromURLArgument]: unrecognized selector sent to instance 0x9e435b0'
Can anybody help me on this...!!!
Thanks In Advance!!!
Yep, you need the -ObjC linker flag in, it's not finding one of the categories from the GoogleOpenSource framework.
See Step 3 in the setup guide: https://developers.google.com/+/mobile/ios/getting-started#step_3_initialize_the_google_client
Basically, in Other Linker Flags, add -ObjC (capitalisation is important, note!). Also make sure you have included both GooglePlus and GoogleOpenSource frameworks in your project.
Add with _objc the other flag called -lc++
I want to send Facebook invites to friends but I don't know why invitation are being shown at the receiving end.
I used this code
NSMutableDictionary* params =
[NSMutableDictionary dictionaryWithObjectsAndKeys:nil];
[FBWebDialogs
presentRequestsDialogModallyWithSession:nil
message:[NSString stringWithFormat:
#"I just smashed friends! %d Can you beat it?",15]
title:#"MSR"
parameters:params
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error) {
if (error) {
// Case A: Error launching the dialog or sending request.
NSLog(#"Error sending request.");
} else {
if (result == FBWebDialogResultDialogNotCompleted) {
// Case B: User clicked the "x" icon
NSLog(#"User canceled request.");
} else {
NSLog(#"Request Sent.");
}
}}];
can any one help me??
Just a guess ->
I used this code in my app but it works perfectly. You can try this.
[FBWebDialogs presentRequestsDialogModallyWithSession:nil
message:#"Please come and try Thot Of U!"
title:#"Invite a Friend"
parameters:nil
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error) {
if (error) {
// Error launching the dialog or sending the request.
NSLog(#"Error sending request.");
} else {
if (result == FBWebDialogResultDialogNotCompleted) {
// User clicked the "x" icon
NSLog(#"User canceled request.");
} else {
// Handle the send request callback
NSDictionary *urlParams = [self parseURLParams:[resultURL query]];
if (![urlParams valueForKey:#"request"]) {
// User clicked the Cancel button
NSLog(#"User canceled request.");
} else {
// User clicked the Send button
NSString *requestID = [urlParams valueForKey:#"request"];
NSLog(#"Request ID: %#", requestID);
}
}
}
}];
I've been trying to experiment with some code from a tutorial, however not having much success due to not getting my head around GCD.
I have an class named API.m and here is the code regarding GCD:
+ (API *) sharedInstance
{
static API *sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
sharedInstance = [[self alloc] initWithBaseURL:[NSURL URLWithString:APIHost]];
});
return sharedInstance;
}
-(void)commandWithParams:(NSMutableDictionary*)params
onCompletion:(JSONResponseBlock)completionBlock
{
NSMutableURLRequest *apiRequest = [self multipartFormRequestWithMethod:#"POST"
path:APIPath
parameters:params
constructingBodyWithBlock: ^(id <AFMultipartFormData>formData) {
//TODO: attach file if needed
}];
AFJSONRequestOperation* operation = [[AFJSONRequestOperation alloc] initWithRequest: apiRequest];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
//success!
completionBlock(responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
//failure :(
completionBlock([NSDictionary dictionaryWithObject:[error localizedDescription] forKey:#"error"]);
}];
[operation start];
}
I make a simple test by implementing a button and getting an NSArray to print it's content to the output window:
- (IBAction)test:(id)sender {
NSMutableDictionary* params =[NSMutableDictionary dictionaryWithObjectsAndKeys:
#"pending", #"command",
[[[API sharedInstance] user] objectForKey:#"UserID"] , #"userID",
nil];
[[API sharedInstance] commandWithParams:params
onCompletion:^(NSDictionary *json) {
//result returned
if ([json objectForKey:#"error"]==nil) {
// Simple example
[self.users addObject:#"1"];
} else {
//error
[UIAlertView title:#"Error" withMessage:[json objectForKey:#"error"]];
}
}];
NSLog(#"%#", self.users);
}
Now when I first click the button an empty NSArray is printed to the output window, but when I press it again it print's "1". It's clear that the program is reaching NSLog before the completion block has time to fully execute. Could someone please help me modify the code so that I have the option to have the NSLog execute after the completion block has finished?
Not sure as to what you are trying to accomplish, but if the goal is to just have NSLog execute after the completion block, you can move the NSLog statement after
[self.users addObject:#"1"];
If you have some code which you want to execute after adding it to the array, you can have
[self methodName]; in the completion block and it will get called there.
Completion block, is the code which is run after execution of the code which you wanted run. The code which you wanted run, will happen asynchronously and on another thread. After that code is run, the completion block code will get executed.
It won't let me attached the params to the request, what am I doing wrong? Params is a Dictionary and endString adds to the sharedClient baseURL.
[[RKClient sharedClient] get:endString usingBlock:^(RKRequest *loader){
loader.params = [RKParams paramsWithDictionary:params];
loader.onDidLoadResponse = ^(RKResponse *response) {
[self parseJSONDictFromResponse:response];
};
loader.onDidFailLoadWithError = ^(NSError *error) {
NSLog(#"error2:%#",error);
};
}];
I get this error:RestKit was asked to retransmit a new body stream for a request. Possible connection error or authentication challenge?
I think you are on the right track. Below is from a working example I found here, about 2/3 the way down the page. Another option for you may be to append the params directly to the URL. I'm not sure if that's feasible for you, but if your parameters are simple then it may be.
- (void)authenticateWithLogin:(NSString *)login password:(NSString *)password onLoad:(RKRequestDidLoadResponseBlock)loadBlock onFail:(RKRequestDidFailLoadWithErrorBlock)failBlock
{
[[RKClient sharedClient] post:#"/login" usingBlock:^(RKRequest *request) {
request.params = [NSDictionary dictionaryWithKeysAndObjects:
#"employee[email]", login,
#"employee[password]", password,
nil];
request.onDidLoadResponse = ^(RKResponse *response) {
id parsedResponse = [response parsedBody:NULL];
NSString *token = [parsedResponse valueForKey:#"authentication_token"];
//NSLog(#"response: [%#] %#", [parsedResponse class], parsedResponse);
if (token.length > 0) {
NSLog(#"response status: %d, token: %#", response.statusCode, token);
[[RKClient sharedClient] setValue:token forHTTPHeaderField:#"X-Rabatme-Auth-Token"];
if (loadBlock) loadBlock(response);
}
[self fireErrorBlock:failBlock onErrorInResponse:response];
};
request.onDidFailLoadWithError = failBlock;
}];
}
You should also take a look at this SO question: RestKit GET query parameters.